pl2303.c revision 430eb0d27c1b36c5191c16b2472b26137673a8d4
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 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty.h> 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty_driver.h> 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty_flip.h> 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/serial.h> 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/moduleparam.h> 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h> 293a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox#include <linux/uaccess.h> 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/usb.h> 31a969888ce91673c7f4b86520d851a6f0d5a5fa7dGreg Kroah-Hartman#include <linux/usb/serial.h> 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "pl2303.h" 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Version Information 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_DESC "Prolific PL2303 USB to serial adaptor driver" 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int debug; 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PL2303_CLOSING_WAIT (30*HZ) 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PL2303_BUF_SIZE 1024 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PL2303_TMP_BUF_SIZE 1024 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct pl2303_buf { 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int buf_size; 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *buf_buf; 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *buf_get; 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *buf_put; 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_device_id id_table [] = { 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) }, 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) }, 563d861494729c70d9ebeb7d93caa107897925c355Peter Moulder { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_DCU11) }, 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ3) }, 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_PHAROS) }, 59b483b6aaa56f0db72fa50e85b6499a32d82009bfMax Arnold { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ALDIGA) }, 604be2fa186d54758296d30c565d7b5111dd45b000Steve Murphy { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MMX) }, 61727df3569b358ef440683787c2b9fe8cc55a0954Greg Kroah-Hartman { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GPRS) }, 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) }, 638a28dea3accda319d51a1bf4d3e280771d946f78Masakazu Mokuno { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) }, 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) }, 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) }, 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) }, 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID_UCSGT) }, 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) }, 6958381719845d9ee19a321c2eb69cfa9b7886be9aWang Jun { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID_2080) }, 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) }, 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) }, 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) }, 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) }, 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) }, 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) }, 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) }, 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) }, 78a8310f3b8b713e52d77c56d4b8865685ee40d02aLuiz Fernando Capitulino { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1) }, 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) }, 80a8310f3b8b713e52d77c56d4b8865685ee40d02aLuiz Fernando Capitulino { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75) }, 81e7beb667842ad0f6ec95a22e7c88e71dfbd60649Andreas Loibl { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) }, 82912299f6f0587bb6c221705ed9949709b36b3c56Alan Cox { USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_ID_S81) }, /* Benq/Siemens S81 */ 83acbb36f116243bed515357264ecbb6ff9c6d2a5bPeter Favrholdt { USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) }, 84c6c27721a42b991965bb792d5c196b8331d008d5Christian Lindner { USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) }, 85c6c27721a42b991965bb792d5c196b8331d008d5Christian Lindner { USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) }, 866cceb05f8df6e28ab90f44bdeba50d33928cdee5Denis MONTERRAT { USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_PRODUCT_ID) }, 87c6c27721a42b991965bb792d5c196b8331d008d5Christian Lindner { USB_DEVICE(LEADTEK_VENDOR_ID, LEADTEK_9531_PRODUCT_ID) }, 88491b04ce1c9adfa0cd73f095086f3c37da81b667Dick Streefland { USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) }, 893b92847425a98d26ad9d2b8682d3ce6020c90752Matthew Meno { USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) }, 90b7aa94b682dc6b6dcdc01d36f8e65cef5aae81e2Kim Oldfield { USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) }, 918fd801339350b63cbb90730ff8b2be349fb3dc67Johannes Steingraeber { USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) }, 922d94b981c7fcb0fba4aa3442cd180066dbedbbc8YOSHIFUJI Hideaki { USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) }, 939e3285dba5cac12d656da66fd7d420ff1bc0ecc0Magnus Damm { USB_DEVICE(COREGA_VENDOR_ID, COREGA_PRODUCT_ID) }, 94cc311ee7d29d96f0bf15599f4456012d6f5ea23cDamien Stuart { USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) }, 957c99200142c04d0f1ed3f048014591f841efdaedMatthew Arnold { USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) }, 96af4b8514aafd53d97b05a0a30b7d4cfd2cbb7b81Mike Provencher { USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) }, 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { } /* Terminating entry */ 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 100372db8a780f63368c6960a167b7a19aad776d704Thiago GalesiMODULE_DEVICE_TABLE(usb, id_table); 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_driver pl2303_driver = { 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = "pl2303", 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .probe = usb_serial_probe, 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .disconnect = usb_serial_disconnect, 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id_table = id_table, 107fcf9e55e066d12c18add7c8a292bf879b45b1d55Sarah Sharp .suspend = usb_serial_suspend, 108fcf9e55e066d12c18add7c8a292bf879b45b1d55Sarah Sharp .resume = usb_serial_resume, 109ba9dc657af86d05d2971633e57d1f6f94ed60472Greg Kroah-Hartman .no_dynamic_id = 1, 110fcf9e55e066d12c18add7c8a292bf879b45b1d55Sarah Sharp .supports_autosuspend = 1, 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_LINE_REQUEST_TYPE 0x21 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_LINE_REQUEST 0x20 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_CONTROL_REQUEST_TYPE 0x21 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_CONTROL_REQUEST 0x22 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONTROL_DTR 0x01 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONTROL_RTS 0x02 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAK_REQUEST_TYPE 0x21 1223a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox#define BREAK_REQUEST 0x23 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAK_ON 0xffff 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAK_OFF 0x0000 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GET_LINE_REQUEST_TYPE 0xa1 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GET_LINE_REQUEST 0x21 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_WRITE_REQUEST_TYPE 0x40 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_WRITE_REQUEST 0x01 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_READ_REQUEST_TYPE 0xc0 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_READ_REQUEST 0x01 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_STATE 0x08 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_STATE_TRANSIENT_MASK 0x74 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_DCD 0x01 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_DSR 0x02 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_BREAK_ERROR 0x04 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_RING 0x08 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_FRAME_ERROR 0x10 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_PARITY_ERROR 0x20 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_OVERRUN_ERROR 0x40 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_CTS 0x80 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum pl2303_type { 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds type_0, /* don't know the difference between type 0 and */ 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds type_1, /* type 1, until someone from prolific tells us... */ 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HX, /* HX version of the pl2303 chip */ 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct pl2303_private { 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spinlock_t lock; 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pl2303_buf *buf; 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int write_urb_in_use; 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wait_queue_head_t delta_msr_wait; 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 line_control; 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 line_status; 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enum pl2303_type type; 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 163572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi/* 164572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * pl2303_buf_alloc 165572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * 166572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Allocate a circular buffer and all associated memory. 167572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi */ 168572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic struct pl2303_buf *pl2303_buf_alloc(unsigned int size) 169572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{ 170572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi struct pl2303_buf *pb; 171572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 172572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi if (size == 0) 173572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi return NULL; 174572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 1755cbded585d129d0226cb48ac4202b253c781be26Robert P. J. Day pb = kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL); 176572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi if (pb == NULL) 177572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi return NULL; 178572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 179572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi pb->buf_buf = kmalloc(size, GFP_KERNEL); 180572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi if (pb->buf_buf == NULL) { 181572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi kfree(pb); 182572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi return NULL; 183572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi } 184572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 185572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi pb->buf_size = size; 186572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi pb->buf_get = pb->buf_put = pb->buf_buf; 187572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 188572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi return pb; 189572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi} 190572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 191572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi/* 192572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * pl2303_buf_free 193572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * 194572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Free the buffer and all associated memory. 195572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi */ 196572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic void pl2303_buf_free(struct pl2303_buf *pb) 197572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{ 198572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi if (pb) { 199572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi kfree(pb->buf_buf); 200572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi kfree(pb); 201572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi } 202572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi} 203572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 204572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi/* 205572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * pl2303_buf_clear 206572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * 207572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Clear out all data in the circular buffer. 208572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi */ 209572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic void pl2303_buf_clear(struct pl2303_buf *pb) 210572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{ 211572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi if (pb != NULL) 212572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi pb->buf_get = pb->buf_put; 213572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi /* equivalent to a get of all data available */ 214572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi} 215572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 216572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi/* 217572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * pl2303_buf_data_avail 218572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * 219572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Return the number of bytes of data available in the circular 220572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * buffer. 221572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi */ 222572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb) 223572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{ 224572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi if (pb == NULL) 225572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi return 0; 226572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 2273a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox return (pb->buf_size + pb->buf_put - pb->buf_get) % pb->buf_size; 228572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi} 229572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 230572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi/* 231572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * pl2303_buf_space_avail 232572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * 233572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Return the number of bytes of space available in the circular 234572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * buffer. 235572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi */ 236572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb) 237572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{ 238572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi if (pb == NULL) 239572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi return 0; 240572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 2413a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox return (pb->buf_size + pb->buf_get - pb->buf_put - 1) % pb->buf_size; 242572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi} 243572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 244572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi/* 245572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * pl2303_buf_put 246572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * 247572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Copy data data from a user buffer and put it into the circular buffer. 248572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Restrict to the amount of space available. 249572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * 250572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Return the number of bytes copied. 251572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi */ 252572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf, 253572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi unsigned int count) 254572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{ 255572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi unsigned int len; 256572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 257572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi if (pb == NULL) 258572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi return 0; 259572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 260572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi len = pl2303_buf_space_avail(pb); 261572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi if (count > len) 262572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi count = len; 263572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 264572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi if (count == 0) 265572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi return 0; 266572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 267572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi len = pb->buf_buf + pb->buf_size - pb->buf_put; 268572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi if (count > len) { 269572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi memcpy(pb->buf_put, buf, len); 270572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi memcpy(pb->buf_buf, buf+len, count - len); 271572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi pb->buf_put = pb->buf_buf + count - len; 272572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi } else { 273572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi memcpy(pb->buf_put, buf, count); 274572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi if (count < len) 275572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi pb->buf_put += count; 276572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi else /* count == len */ 277572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi pb->buf_put = pb->buf_buf; 278572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi } 279572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 280572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi return count; 281572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi} 282572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 283572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi/* 284572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * pl2303_buf_get 285572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * 286572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Get data from the circular buffer and copy to the given buffer. 287572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Restrict to the amount of data available. 288572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * 289572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Return the number of bytes copied. 290572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi */ 291572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf, 292572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi unsigned int count) 293572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{ 294572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi unsigned int len; 295572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 296572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi if (pb == NULL) 297572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi return 0; 298572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 299572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi len = pl2303_buf_data_avail(pb); 300572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi if (count > len) 301572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi count = len; 302572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 303572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi if (count == 0) 304572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi return 0; 305572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 306572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi len = pb->buf_buf + pb->buf_size - pb->buf_get; 307572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi if (count > len) { 308572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi memcpy(buf, pb->buf_get, len); 309572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi memcpy(buf+len, pb->buf_buf, count - len); 310572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi pb->buf_get = pb->buf_buf + count - len; 311572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi } else { 312572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi memcpy(buf, pb->buf_get, count); 313572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi if (count < len) 314572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi pb->buf_get += count; 315572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi else /* count == len */ 316572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi pb->buf_get = pb->buf_buf; 317572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi } 318572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 319572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi return count; 320572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi} 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 322eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharpstatic int pl2303_vendor_read(__u16 value, __u16 index, 323eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp struct usb_serial *serial, unsigned char *buf) 324eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp{ 325eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp int res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), 326eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE, 327eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp value, index, buf, 1, 100); 328eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp dbg("0x%x:0x%x:0x%x:0x%x %d - %x", VENDOR_READ_REQUEST_TYPE, 329eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp VENDOR_READ_REQUEST, value, index, res, buf[0]); 330eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp return res; 331eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp} 332eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp 333eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharpstatic int pl2303_vendor_write(__u16 value, __u16 index, 334eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp struct usb_serial *serial) 335eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp{ 336eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp int res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 337eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE, 338eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp value, index, NULL, 0, 100); 339eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp dbg("0x%x:0x%x:0x%x:0x%x %d", VENDOR_WRITE_REQUEST_TYPE, 340eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp VENDOR_WRITE_REQUEST, value, index, res); 341eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp return res; 342eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp} 343eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp 344372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic int pl2303_startup(struct usb_serial *serial) 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pl2303_private *priv; 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enum pl2303_type type = type_0; 3483e152505a57db6622deb1322c22551c046e33d16Sarah Sharp unsigned char *buf; 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3513e152505a57db6622deb1322c22551c046e33d16Sarah Sharp buf = kmalloc(10, GFP_KERNEL); 3523e152505a57db6622deb1322c22551c046e33d16Sarah Sharp if (buf == NULL) 3533e152505a57db6622deb1322c22551c046e33d16Sarah Sharp return -ENOMEM; 3543e152505a57db6622deb1322c22551c046e33d16Sarah Sharp 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (serial->dev->descriptor.bDeviceClass == 0x02) 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds type = type_0; 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40) 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds type = HX; 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (serial->dev->descriptor.bDeviceClass == 0x00) 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds type = type_1; 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (serial->dev->descriptor.bDeviceClass == 0xFF) 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds type = type_1; 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("device type: %d", type); 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < serial->num_ports; ++i) { 36680b6ca48321974a6566a1c9048ba34f60420bca6Eric Sesterhenn priv = kzalloc(sizeof(struct pl2303_private), GFP_KERNEL); 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!priv) 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto cleanup; 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_init(&priv->lock); 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->buf = pl2303_buf_alloc(PL2303_BUF_SIZE); 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (priv->buf == NULL) { 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(priv); 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto cleanup; 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_waitqueue_head(&priv->delta_msr_wait); 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->type = type; 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_set_serial_port_data(serial->port[i], priv); 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3793e152505a57db6622deb1322c22551c046e33d16Sarah Sharp 3803e152505a57db6622deb1322c22551c046e33d16Sarah Sharp pl2303_vendor_read(0x8484, 0, serial, buf); 3813e152505a57db6622deb1322c22551c046e33d16Sarah Sharp pl2303_vendor_write(0x0404, 0, serial); 3823e152505a57db6622deb1322c22551c046e33d16Sarah Sharp pl2303_vendor_read(0x8484, 0, serial, buf); 3833e152505a57db6622deb1322c22551c046e33d16Sarah Sharp pl2303_vendor_read(0x8383, 0, serial, buf); 3843e152505a57db6622deb1322c22551c046e33d16Sarah Sharp pl2303_vendor_read(0x8484, 0, serial, buf); 3853e152505a57db6622deb1322c22551c046e33d16Sarah Sharp pl2303_vendor_write(0x0404, 1, serial); 3863e152505a57db6622deb1322c22551c046e33d16Sarah Sharp pl2303_vendor_read(0x8484, 0, serial, buf); 3873e152505a57db6622deb1322c22551c046e33d16Sarah Sharp pl2303_vendor_read(0x8383, 0, serial, buf); 3883e152505a57db6622deb1322c22551c046e33d16Sarah Sharp pl2303_vendor_write(0, 1, serial); 3893e152505a57db6622deb1322c22551c046e33d16Sarah Sharp pl2303_vendor_write(1, 0, serial); 3903e152505a57db6622deb1322c22551c046e33d16Sarah Sharp if (type == HX) 3913e152505a57db6622deb1322c22551c046e33d16Sarah Sharp pl2303_vendor_write(2, 0x44, serial); 3923e152505a57db6622deb1322c22551c046e33d16Sarah Sharp else 3933e152505a57db6622deb1322c22551c046e33d16Sarah Sharp pl2303_vendor_write(2, 0x24, serial); 3943e152505a57db6622deb1322c22551c046e33d16Sarah Sharp 3953e152505a57db6622deb1322c22551c046e33d16Sarah Sharp kfree(buf); 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscleanup: 3993e152505a57db6622deb1322c22551c046e33d16Sarah Sharp kfree(buf); 4003a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox for (--i; i >= 0; --i) { 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv = usb_get_serial_port_data(serial->port[i]); 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pl2303_buf_free(priv->buf); 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(priv); 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_set_serial_port_data(serial->port[i], NULL); 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 409372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic int set_control_lines(struct usb_device *dev, u8 value) 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 4123a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox 413372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 414372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE, 415372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi value, 0, NULL, 0, 100); 416441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - value = %d, retval = %d", __func__, value, retval); 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pl2303_send(struct usb_serial_port *port) 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int count, result; 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pl2303_private *priv = usb_get_serial_port_data(port); 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 426441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - port %d", __func__, port->number); 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&priv->lock, flags); 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (priv->write_urb_in_use) { 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count = pl2303_buf_get(priv->buf, port->write_urb->transfer_buffer, 436372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi port->bulk_out_size); 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (count == 0) { 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->write_urb_in_use = 1; 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 447441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison usb_serial_debug_data(debug, &port->dev, __func__, count, 448372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi port->write_urb->transfer_buffer); 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->write_urb->transfer_buffer_length = count; 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->write_urb->dev = port->serial->dev; 452372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi result = usb_submit_urb(port->write_urb, GFP_ATOMIC); 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) { 454372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi dev_err(&port->dev, "%s - failed submitting write urb," 455441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison " error %d\n", __func__, result); 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->write_urb_in_use = 0; 4573a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox /* TODO: reschedule pl2303_send */ 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 460cf2c7481d2ff7f0c266de873b2fe93883e9782f9Pete Zaitcev usb_serial_port_softint(port); 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 46395da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic int pl2303_write(struct tty_struct *tty, struct usb_serial_port *port, 46495da310e66ee8090119596c70ca8432e57f9a97fAlan Cox const unsigned char *buf, int count) 465572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{ 466572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi struct pl2303_private *priv = usb_get_serial_port_data(port); 467572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi unsigned long flags; 468572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 469441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - port %d, %d bytes", __func__, port->number, count); 470572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 471572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi if (!count) 472572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi return count; 473572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 474572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi spin_lock_irqsave(&priv->lock, flags); 475572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi count = pl2303_buf_put(priv->buf, buf, count); 476572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi spin_unlock_irqrestore(&priv->lock, flags); 477572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 478572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi pl2303_send(port); 479572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 480572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi return count; 481572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi} 482572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 48395da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic int pl2303_write_room(struct tty_struct *tty) 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 48595da310e66ee8090119596c70ca8432e57f9a97fAlan Cox struct usb_serial_port *port = tty->driver_data; 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pl2303_private *priv = usb_get_serial_port_data(port); 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int room = 0; 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 490441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - port %d", __func__, port->number); 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&priv->lock, flags); 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds room = pl2303_buf_space_avail(priv->buf); 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 496441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - returns %d", __func__, room); 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return room; 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 50095da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic int pl2303_chars_in_buffer(struct tty_struct *tty) 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 50295da310e66ee8090119596c70ca8432e57f9a97fAlan Cox struct usb_serial_port *port = tty->driver_data; 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pl2303_private *priv = usb_get_serial_port_data(port); 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int chars = 0; 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 507441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - port %d", __func__, port->number); 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&priv->lock, flags); 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds chars = pl2303_buf_data_avail(priv->buf); 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 513441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - returns %d", __func__, chars); 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return chars; 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 51795da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic void pl2303_set_termios(struct tty_struct *tty, 51895da310e66ee8090119596c70ca8432e57f9a97fAlan Cox struct usb_serial_port *port, struct ktermios *old_termios) 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_serial *serial = port->serial; 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pl2303_private *priv = usb_get_serial_port_data(port); 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int cflag; 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *buf; 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int baud; 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 control; 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 529441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - port %d", __func__, port->number); 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 531bf5e5834bffc62b50cd4a201804506eb11ef1af8Alan Cox /* The PL2303 is reported to lose bytes if you change 532bf5e5834bffc62b50cd4a201804506eb11ef1af8Alan Cox serial settings even to the same values as before. Thus 533bf5e5834bffc62b50cd4a201804506eb11ef1af8Alan Cox we actually need to filter in this specific case */ 534bf5e5834bffc62b50cd4a201804506eb11ef1af8Alan Cox 53595da310e66ee8090119596c70ca8432e57f9a97fAlan Cox if (!tty_termios_hw_change(tty->termios, old_termios)) 536bf5e5834bffc62b50cd4a201804506eb11ef1af8Alan Cox return; 537bf5e5834bffc62b50cd4a201804506eb11ef1af8Alan Cox 53895da310e66ee8090119596c70ca8432e57f9a97fAlan Cox cflag = tty->termios->c_cflag; 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 540372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi buf = kzalloc(7, GFP_KERNEL); 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!buf) { 542441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dev_err(&port->dev, "%s - out of memory.\n", __func__); 543a5b6f60c5a30c494017c7a2d11c4067f90d3d0dfAlan Cox /* Report back no change occurred */ 54495da310e66ee8090119596c70ca8432e57f9a97fAlan Cox *tty->termios = *old_termios; 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 548372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), 549372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE, 550372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi 0, 0, buf, 7, 100); 551372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i, 552372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cflag & CSIZE) { 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cflag & CSIZE) { 5563a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox case CS5: 5573a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox buf[6] = 5; 5583a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox break; 5593a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox case CS6: 5603a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox buf[6] = 6; 5613a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox break; 5623a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox case CS7: 5633a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox buf[6] = 7; 5643a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox break; 5653a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox default: 5663a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox case CS8: 5673a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox buf[6] = 8; 5683a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox break; 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 570441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - data bits = %d", __func__, buf[6]); 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 57395da310e66ee8090119596c70ca8432e57f9a97fAlan Cox baud = tty_get_baud_rate(tty); 574441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - baud = %d", __func__, baud); 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (baud) { 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[0] = baud & 0xff; 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[1] = (baud >> 8) & 0xff; 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[2] = (baud >> 16) & 0xff; 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[3] = (baud >> 24) & 0xff; 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* For reference buf[4]=0 is 1 stop bits */ 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* For reference buf[4]=1 is 1.5 stop bits */ 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* For reference buf[4]=2 is 2 stop bits */ 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cflag & CSTOPB) { 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[4] = 2; 587441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - stop bits = 2", __func__); 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[4] = 0; 590441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - stop bits = 1", __func__); 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cflag & PARENB) { 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* For reference buf[5]=0 is none parity */ 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* For reference buf[5]=1 is odd parity */ 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* For reference buf[5]=2 is even parity */ 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* For reference buf[5]=3 is mark parity */ 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* For reference buf[5]=4 is space parity */ 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cflag & PARODD) { 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[5] = 1; 601441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - parity = odd", __func__); 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[5] = 2; 604441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - parity = even", __func__); 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[5] = 0; 608441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - parity = none", __func__); 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 611372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 612372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE, 613372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi 0, 0, buf, 7, 100); 614372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi dbg("0x21:0x20:0:0 %d", i); 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* change control lines if we are switching to or from B0 */ 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&priv->lock, flags); 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds control = priv->line_control; 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((cflag & CBAUD) == B0) 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS); 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->line_control |= (CONTROL_DTR | CONTROL_RTS); 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (control != priv->line_control) { 6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds control = priv->line_control; 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_control_lines(serial->dev, control); 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 630372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0; 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 633372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), 634372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE, 635372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi 0, 0, buf, 7, 100); 636372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i, 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cflag & CRTSCTS) { 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (priv->type == HX) 641eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp pl2303_vendor_write(0x0, 0x61, serial); 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 643eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp pl2303_vendor_write(0x0, 0x41, serial); 644715f9527c1c1edd1a9c7a55ab4535211279c9374t.sefzick } else { 645eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp pl2303_vendor_write(0x0, 0x0, serial); 6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 647572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 648df64c47184aedf34fd2a69a4b7f68584fe982fdfAlan Cox /* FIXME: Need to read back resulting baud rate */ 649df64c47184aedf34fd2a69a4b7f68584fe982fdfAlan Cox if (baud) 65095da310e66ee8090119596c70ca8432e57f9a97fAlan Cox tty_encode_baud_rate(tty, baud, baud); 651df64c47184aedf34fd2a69a4b7f68584fe982fdfAlan Cox 652572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi kfree(buf); 653572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi} 654572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 655335f8514f200e63d689113d29cb7253a5c282967Alan Coxstatic void pl2303_dtr_rts(struct usb_serial_port *port, int on) 656335f8514f200e63d689113d29cb7253a5c282967Alan Cox{ 657335f8514f200e63d689113d29cb7253a5c282967Alan Cox struct pl2303_private *priv = usb_get_serial_port_data(port); 658335f8514f200e63d689113d29cb7253a5c282967Alan Cox unsigned long flags; 659335f8514f200e63d689113d29cb7253a5c282967Alan Cox u8 control; 660335f8514f200e63d689113d29cb7253a5c282967Alan Cox 661335f8514f200e63d689113d29cb7253a5c282967Alan Cox spin_lock_irqsave(&priv->lock, flags); 662335f8514f200e63d689113d29cb7253a5c282967Alan Cox /* Change DTR and RTS */ 663335f8514f200e63d689113d29cb7253a5c282967Alan Cox if (on) 664335f8514f200e63d689113d29cb7253a5c282967Alan Cox priv->line_control |= (CONTROL_DTR | CONTROL_RTS); 665335f8514f200e63d689113d29cb7253a5c282967Alan Cox else 666335f8514f200e63d689113d29cb7253a5c282967Alan Cox priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS); 667335f8514f200e63d689113d29cb7253a5c282967Alan Cox control = priv->line_control; 668335f8514f200e63d689113d29cb7253a5c282967Alan Cox spin_unlock_irqrestore(&priv->lock, flags); 669335f8514f200e63d689113d29cb7253a5c282967Alan Cox set_control_lines(port->serial->dev, control); 670335f8514f200e63d689113d29cb7253a5c282967Alan Cox} 671335f8514f200e63d689113d29cb7253a5c282967Alan Cox 672335f8514f200e63d689113d29cb7253a5c282967Alan Coxstatic void pl2303_close(struct usb_serial_port *port) 673572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{ 674572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi struct pl2303_private *priv = usb_get_serial_port_data(port); 675572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi unsigned long flags; 676572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 677441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - port %d", __func__, port->number); 678572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 679572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi spin_lock_irqsave(&priv->lock, flags); 680572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi /* clear out any remaining data in the buffer */ 681572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi pl2303_buf_clear(priv->buf); 682572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi spin_unlock_irqrestore(&priv->lock, flags); 683572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 684572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi /* shutdown our urbs */ 685441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - shutting down urbs", __func__); 686572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi usb_kill_urb(port->write_urb); 687572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi usb_kill_urb(port->read_urb); 688572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi usb_kill_urb(port->interrupt_in_urb); 689572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 69295da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic int pl2303_open(struct tty_struct *tty, 69395da310e66ee8090119596c70ca8432e57f9a97fAlan Cox struct usb_serial_port *port, struct file *filp) 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 695606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox struct ktermios tmp_termios; 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_serial *serial = port->serial; 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pl2303_private *priv = usb_get_serial_port_data(port); 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result; 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 700441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - port %d", __func__, port->number); 7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7021694899fd1af43636351aac97f415fd3c9cefb1dDariusz M if (priv->type != HX) { 7031694899fd1af43636351aac97f415fd3c9cefb1dDariusz M usb_clear_halt(serial->dev, port->write_urb->pipe); 7041694899fd1af43636351aac97f415fd3c9cefb1dDariusz M usb_clear_halt(serial->dev, port->read_urb->pipe); 7053e152505a57db6622deb1322c22551c046e33d16Sarah Sharp } else { 7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* reset upstream data pipes */ 707eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp pl2303_vendor_write(8, 0, serial); 708eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp pl2303_vendor_write(9, 0, serial); 7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Setup termios */ 71295da310e66ee8090119596c70ca8432e57f9a97fAlan Cox if (tty) 71395da310e66ee8090119596c70ca8432e57f9a97fAlan Cox pl2303_set_termios(tty, port, &tmp_termios); 7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7153a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox /* FIXME: need to assert RTS and DTR if CRTSCTS off */ 7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 717441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - submitting read urb", __func__); 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->read_urb->dev = serial->dev; 719372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi result = usb_submit_urb(port->read_urb, GFP_KERNEL); 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) { 721372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi dev_err(&port->dev, "%s - failed submitting read urb," 722441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison " error %d\n", __func__, result); 723335f8514f200e63d689113d29cb7253a5c282967Alan Cox pl2303_close(port); 7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EPROTO; 7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 727441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - submitting interrupt urb", __func__); 7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->interrupt_in_urb->dev = serial->dev; 729372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); 7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) { 731372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi dev_err(&port->dev, "%s - failed submitting interrupt urb," 732441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison " error %d\n", __func__, result); 733335f8514f200e63d689113d29cb7253a5c282967Alan Cox pl2303_close(port); 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EPROTO; 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 736335f8514f200e63d689113d29cb7253a5c282967Alan Cox port->port.drain_delay = 256; 7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 74095da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic int pl2303_tiocmset(struct tty_struct *tty, struct file *file, 741372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi unsigned int set, unsigned int clear) 7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 74395da310e66ee8090119596c70ca8432e57f9a97fAlan Cox struct usb_serial_port *port = tty->driver_data; 7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pl2303_private *priv = usb_get_serial_port_data(port); 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 control; 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7486fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner if (!usb_get_intfdata(port->serial->interface)) 7496fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner return -ENODEV; 7506fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner 751372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi spin_lock_irqsave(&priv->lock, flags); 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (set & TIOCM_RTS) 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->line_control |= CONTROL_RTS; 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (set & TIOCM_DTR) 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->line_control |= CONTROL_DTR; 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (clear & TIOCM_RTS) 7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->line_control &= ~CONTROL_RTS; 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (clear & TIOCM_DTR) 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->line_control &= ~CONTROL_DTR; 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds control = priv->line_control; 761372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi spin_unlock_irqrestore(&priv->lock, flags); 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 763372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi return set_control_lines(port->serial->dev, control); 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 76695da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic int pl2303_tiocmget(struct tty_struct *tty, struct file *file) 7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 76895da310e66ee8090119596c70ca8432e57f9a97fAlan Cox struct usb_serial_port *port = tty->driver_data; 7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pl2303_private *priv = usb_get_serial_port_data(port); 7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int mcr; 7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int status; 7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int result; 7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 775441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s (%d)", __func__, port->number); 7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7776fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner if (!usb_get_intfdata(port->serial->interface)) 7786fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner return -ENODEV; 7796fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner 780372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi spin_lock_irqsave(&priv->lock, flags); 7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mcr = priv->line_control; 7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = priv->line_status; 783372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi spin_unlock_irqrestore(&priv->lock, flags); 7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = ((mcr & CONTROL_DTR) ? TIOCM_DTR : 0) 7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | ((mcr & CONTROL_RTS) ? TIOCM_RTS : 0) 7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | ((status & UART_CTS) ? TIOCM_CTS : 0) 7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | ((status & UART_DSR) ? TIOCM_DSR : 0) 7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | ((status & UART_RING) ? TIOCM_RI : 0) 7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | ((status & UART_DCD) ? TIOCM_CD : 0); 7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 792441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - result = %x", __func__, result); 7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return result; 7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 797335f8514f200e63d689113d29cb7253a5c282967Alan Coxstatic int pl2303_carrier_raised(struct usb_serial_port *port) 798335f8514f200e63d689113d29cb7253a5c282967Alan Cox{ 799335f8514f200e63d689113d29cb7253a5c282967Alan Cox struct pl2303_private *priv = usb_get_serial_port_data(port); 800335f8514f200e63d689113d29cb7253a5c282967Alan Cox if (priv->line_status & UART_DCD) 801335f8514f200e63d689113d29cb7253a5c282967Alan Cox return 1; 802335f8514f200e63d689113d29cb7253a5c282967Alan Cox return 0; 803335f8514f200e63d689113d29cb7253a5c282967Alan Cox} 804335f8514f200e63d689113d29cb7253a5c282967Alan Cox 8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int wait_modem_info(struct usb_serial_port *port, unsigned int arg) 8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pl2303_private *priv = usb_get_serial_port_data(port); 8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int prevstatus; 8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int status; 8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int changed; 8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 813372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi spin_lock_irqsave(&priv->lock, flags); 8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds prevstatus = priv->line_status; 815372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi spin_unlock_irqrestore(&priv->lock, flags); 8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (1) { 8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds interruptible_sleep_on(&priv->delta_msr_wait); 8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* see if a signal did it */ 8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (signal_pending(current)) 8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ERESTARTSYS; 822372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi 823372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi spin_lock_irqsave(&priv->lock, flags); 8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = priv->line_status; 825372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi spin_unlock_irqrestore(&priv->lock, flags); 826372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi 8273a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox changed = prevstatus ^ status; 828372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi 8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (((arg & TIOCM_RNG) && (changed & UART_RING)) || 8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((arg & TIOCM_DSR) && (changed & UART_DSR)) || 8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((arg & TIOCM_CD) && (changed & UART_DCD)) || 8323a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox ((arg & TIOCM_CTS) && (changed & UART_CTS))) { 8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds prevstatus = status; 8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* NOTREACHED */ 8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 84195da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic int pl2303_ioctl(struct tty_struct *tty, struct file *file, 842372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi unsigned int cmd, unsigned long arg) 8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 84495da310e66ee8090119596c70ca8432e57f9a97fAlan Cox struct usb_serial_port *port = tty->driver_data; 845441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd); 8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cmd) { 8483a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox case TIOCMIWAIT: 8493a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox dbg("%s (%d) TIOCMIWAIT", __func__, port->number); 8503a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox return wait_modem_info(port, arg); 8513a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox default: 8523a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox dbg("%s not supported = 0x%04x", __func__, cmd); 8533a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox break; 8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOIOCTLCMD; 8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 85895da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic void pl2303_break_ctl(struct tty_struct *tty, int break_state) 8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 86095da310e66ee8090119596c70ca8432e57f9a97fAlan Cox struct usb_serial_port *port = tty->driver_data; 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_serial *serial = port->serial; 8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 state; 8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result; 8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 865441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - port %d", __func__, port->number); 8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (break_state == 0) 8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds state = BREAK_OFF; 8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds state = BREAK_ON; 8713a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox dbg("%s - turning break %s", __func__, 8723a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox state == BREAK_OFF ? "off" : "on"); 8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 874372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 875372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi BREAK_REQUEST, BREAK_REQUEST_TYPE, state, 876372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi 0, NULL, 0, 100); 8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) 878441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - error sending break = %d", __func__, result); 8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 881372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic void pl2303_shutdown(struct usb_serial *serial) 8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pl2303_private *priv; 8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 886441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s", __func__); 8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < serial->num_ports; ++i) { 8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv = usb_get_serial_port_data(serial->port[i]); 8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (priv) { 8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pl2303_buf_free(priv->buf); 8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(priv); 8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_set_serial_port_data(serial->port[i], NULL); 8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 895372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi } 8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 89897bb13ec5bc156352cca8af90080597e04299a73Flavio Leitnerstatic void pl2303_update_line_status(struct usb_serial_port *port, 89997bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner unsigned char *data, 90097bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner unsigned int actual_length) 90197bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner{ 90297bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner 90397bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner struct pl2303_private *priv = usb_get_serial_port_data(port); 90497bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner unsigned long flags; 90597bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner u8 status_idx = UART_STATE; 90695f209f93663103db2a8fb989e226ac68a98b036Horst Schirmeier u8 length = UART_STATE + 1; 9079c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi u16 idv, idp; 90897bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner 9099c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi idv = le16_to_cpu(port->serial->dev->descriptor.idVendor); 9109c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi idp = le16_to_cpu(port->serial->dev->descriptor.idProduct); 9119c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi 9129c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi 9139c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi if (idv == SIEMENS_VENDOR_ID) { 9149c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi if (idp == SIEMENS_PRODUCT_ID_X65 || 9159c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi idp == SIEMENS_PRODUCT_ID_SX1 || 9169c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi idp == SIEMENS_PRODUCT_ID_X75) { 9179c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi 9189c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi length = 1; 9199c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi status_idx = 0; 9209c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi } 92197bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner } 92297bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner 92397bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner if (actual_length < length) 924a009b75aa0ed55f0bc473c8a3b3e872cbca807ecLuiz Fernando N. Capitulino return; 92597bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner 9263a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox /* Save off the uart status for others to look at */ 92797bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner spin_lock_irqsave(&priv->lock, flags); 92897bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner priv->line_status = data[status_idx]; 92997bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner spin_unlock_irqrestore(&priv->lock, flags); 930430eb0d27c1b36c5191c16b2472b26137673a8d4Jason Wessel if (priv->line_status & UART_BREAK_ERROR) 931430eb0d27c1b36c5191c16b2472b26137673a8d4Jason Wessel usb_serial_handle_break(port); 932372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi wake_up_interruptible(&priv->delta_msr_wait); 93397bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner} 9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9357d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void pl2303_read_int_callback(struct urb *urb) 9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 937cdc97792289179974af6dda781c855696358d307Ming Lei struct usb_serial_port *port = urb->context; 9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *data = urb->transfer_buffer; 93997bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner unsigned int actual_length = urb->actual_length; 940461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman int status = urb->status; 941461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman int retval; 9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 943441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s (%d)", __func__, port->number); 9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 945461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman switch (status) { 9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0: 9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* success */ 9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -ECONNRESET: 9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -ENOENT: 9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -ESHUTDOWN: 9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* this urb is terminated, clean up */ 953441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - urb shutting down with status: %d", __func__, 954461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman status); 9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 957441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - nonzero urb status received: %d", __func__, 958461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman status); 9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 962441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison usb_serial_debug_data(debug, &port->dev, __func__, 963372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi urb->actual_length, urb->transfer_buffer); 964372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi 96597bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner pl2303_update_line_status(port, data, actual_length); 9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit: 968461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman retval = usb_submit_urb(urb, GFP_ATOMIC); 969461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman if (retval) 970372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi dev_err(&urb->dev->dev, 971372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi "%s - usb_submit_urb failed with result %d\n", 972441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison __func__, retval); 9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9757d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void pl2303_read_bulk_callback(struct urb *urb) 9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 977cdc97792289179974af6dda781c855696358d307Ming Lei struct usb_serial_port *port = urb->context; 9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pl2303_private *priv = usb_get_serial_port_data(port); 9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct tty_struct *tty; 9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *data = urb->transfer_buffer; 9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result; 984461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman int status = urb->status; 985461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman u8 line_status; 9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char tty_flag; 9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 988441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - port %d", __func__, port->number); 9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 990461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman if (status) { 991441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - urb status = %d", __func__, status); 99295da310e66ee8090119596c70ca8432e57f9a97fAlan Cox if (!port->port.count) { 993441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - port is closed, exiting.", __func__); 9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 996461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman if (status == -EPROTO) { 997372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi /* PL2303 mysteriously fails with -EPROTO reschedule 998372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi * the read */ 999372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi dbg("%s - caught -EPROTO, resubmitting the urb", 1000441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison __func__); 10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb->dev = port->serial->dev; 10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = usb_submit_urb(urb, GFP_ATOMIC); 10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) 1004372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi dev_err(&urb->dev->dev, "%s - failed" 1005372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi " resubmitting read urb, error %d\n", 1006441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison __func__, result); 10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1009441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - unable to handle the error, exiting.", __func__); 10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1013441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison usb_serial_debug_data(debug, &port->dev, __func__, 1014372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi urb->actual_length, data); 10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* get tty_flag from status */ 10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty_flag = TTY_NORMAL; 10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&priv->lock, flags); 1020461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman line_status = priv->line_status; 10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->line_status &= ~UART_STATE_TRANSIENT_MASK; 10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 1023372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi wake_up_interruptible(&priv->delta_msr_wait); 10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* break takes precedence over parity, */ 10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* which takes precedence over framing errors */ 10273a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox if (line_status & UART_BREAK_ERROR) 10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty_flag = TTY_BREAK; 1029461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman else if (line_status & UART_PARITY_ERROR) 10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty_flag = TTY_PARITY; 1031461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman else if (line_status & UART_FRAME_ERROR) 10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty_flag = TTY_FRAME; 1033441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - tty_flag = %d", __func__, tty_flag); 10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10354a90f09b20f4622dcbff1f0e1e6bae1704f8ad8cAlan Cox tty = tty_port_tty_get(&port->port); 10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tty && urb->actual_length) { 103733f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox tty_buffer_request_room(tty, urb->actual_length + 1); 10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* overrun is special, not associated with a char */ 1039461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman if (line_status & UART_OVERRUN_ERROR) 10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty_insert_flip_char(tty, 0, TTY_OVERRUN); 104133f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox for (i = 0; i < urb->actual_length; ++i) 1042430eb0d27c1b36c5191c16b2472b26137673a8d4Jason Wessel if (!usb_serial_handle_sysrq_char(port, data[i])) 1043430eb0d27c1b36c5191c16b2472b26137673a8d4Jason Wessel tty_insert_flip_char(tty, data[i], tty_flag); 1044372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi tty_flip_buffer_push(tty); 10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10464a90f09b20f4622dcbff1f0e1e6bae1704f8ad8cAlan Cox tty_kref_put(tty); 10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Schedule the next read _if_ we are still open */ 104895da310e66ee8090119596c70ca8432e57f9a97fAlan Cox if (port->port.count) { 10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb->dev = port->serial->dev; 10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = usb_submit_urb(urb, GFP_ATOMIC); 10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) 1052372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi dev_err(&urb->dev->dev, "%s - failed resubmitting" 1053441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison " read urb, error %d\n", __func__, result); 10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10597d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void pl2303_write_bulk_callback(struct urb *urb) 10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1061cdc97792289179974af6dda781c855696358d307Ming Lei struct usb_serial_port *port = urb->context; 10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pl2303_private *priv = usb_get_serial_port_data(port); 10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result; 1064461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman int status = urb->status; 10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1066441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - port %d", __func__, port->number); 10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1068461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman switch (status) { 10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0: 10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* success */ 10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -ECONNRESET: 10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -ENOENT: 10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -ESHUTDOWN: 10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* this urb is terminated, clean up */ 1076441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - urb shutting down with status: %d", __func__, 1077461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman status); 10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->write_urb_in_use = 0; 10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* error in the urb, so we have to resubmit it */ 1082441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - Overflow in write", __func__); 1083441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - nonzero write bulk status received: %d", __func__, 1084461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman status); 10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->write_urb->transfer_buffer_length = 1; 10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->write_urb->dev = port->serial->dev; 1087372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi result = usb_submit_urb(port->write_urb, GFP_ATOMIC); 10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) 1089372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi dev_err(&urb->dev->dev, "%s - failed resubmitting write" 1090441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison " urb, error %d\n", __func__, result); 10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->write_urb_in_use = 0; 10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* send any buffered data */ 10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pl2303_send(port); 10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1101572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi/* All of the device info needed for the PL2303 SIO serial converter */ 1102572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic struct usb_serial_driver pl2303_device = { 1103572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .driver = { 1104572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .owner = THIS_MODULE, 1105572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .name = "pl2303", 1106572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi }, 1107572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .id_table = id_table, 1108d9b1b787736852f462dbf277b3ca708cbbf693aeJohannes Hölzl .usb_driver = &pl2303_driver, 1109572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .num_ports = 1, 1110572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .open = pl2303_open, 1111572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .close = pl2303_close, 1112335f8514f200e63d689113d29cb7253a5c282967Alan Cox .dtr_rts = pl2303_dtr_rts, 1113335f8514f200e63d689113d29cb7253a5c282967Alan Cox .carrier_raised = pl2303_carrier_raised, 1114572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .write = pl2303_write, 1115572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .ioctl = pl2303_ioctl, 1116572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .break_ctl = pl2303_break_ctl, 1117572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .set_termios = pl2303_set_termios, 1118572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .tiocmget = pl2303_tiocmget, 1119572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .tiocmset = pl2303_tiocmset, 1120572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .read_bulk_callback = pl2303_read_bulk_callback, 1121572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .read_int_callback = pl2303_read_int_callback, 1122572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .write_bulk_callback = pl2303_write_bulk_callback, 1123572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .write_room = pl2303_write_room, 1124572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .chars_in_buffer = pl2303_chars_in_buffer, 1125572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .attach = pl2303_startup, 1126572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .shutdown = pl2303_shutdown, 1127572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi}; 11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1129372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic int __init pl2303_init(void) 11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 1132372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi 11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = usb_serial_register(&pl2303_device); 11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) 11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto failed_usb_serial_register; 11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = usb_register(&pl2303_driver); 11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) 11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto failed_usb_register; 1139c197a8db59daf06dc5e77acd5a9681329cb22458Greg Kroah-Hartman printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n"); 11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfailed_usb_register: 11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_serial_deregister(&pl2303_device); 11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfailed_usb_serial_register: 11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1147372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic void __exit pl2303_exit(void) 11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1149372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi usb_deregister(&pl2303_driver); 1150372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi usb_serial_deregister(&pl2303_device); 11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(pl2303_init); 11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(pl2303_exit); 11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION(DRIVER_DESC); 11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(debug, bool, S_IRUGO | S_IWUSR); 11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(debug, "Debug enabled or not"); 11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1162