pl2303.c revision 461d696aeeae294ad22dfcaae462d1757f955778
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 * 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * See Documentation/usb/usb-serial.txt for more information on using this driver 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty.h> 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty_driver.h> 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty_flip.h> 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/serial.h> 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/moduleparam.h> 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h> 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h> 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/usb.h> 30a969888ce91673c7f4b86520d851a6f0d5a5fa7dGreg Kroah-Hartman#include <linux/usb/serial.h> 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "pl2303.h" 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Version Information 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_DESC "Prolific PL2303 USB to serial adaptor driver" 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int debug; 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PL2303_CLOSING_WAIT (30*HZ) 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PL2303_BUF_SIZE 1024 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PL2303_TMP_BUF_SIZE 1024 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct pl2303_buf { 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int buf_size; 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *buf_buf; 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *buf_get; 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *buf_put; 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_device_id id_table [] = { 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) }, 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) }, 553d861494729c70d9ebeb7d93caa107897925c355Peter Moulder { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_DCU11) }, 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ3) }, 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_PHAROS) }, 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) }, 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) }, 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) }, 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) }, 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID_UCSGT) }, 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) }, 6458381719845d9ee19a321c2eb69cfa9b7886be9aWang Jun { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID_2080) }, 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) }, 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) }, 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) }, 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) }, 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) }, 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) }, 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) }, 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) }, 73a8310f3b8b713e52d77c56d4b8865685ee40d02aLuiz Fernando Capitulino { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1) }, 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) }, 75a8310f3b8b713e52d77c56d4b8865685ee40d02aLuiz Fernando Capitulino { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75) }, 76acbb36f116243bed515357264ecbb6ff9c6d2a5bPeter Favrholdt { USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) }, 77c6c27721a42b991965bb792d5c196b8331d008d5Christian Lindner { USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) }, 78c6c27721a42b991965bb792d5c196b8331d008d5Christian Lindner { USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) }, 796cceb05f8df6e28ab90f44bdeba50d33928cdee5Denis MONTERRAT { USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_PRODUCT_ID) }, 80c6c27721a42b991965bb792d5c196b8331d008d5Christian Lindner { USB_DEVICE(LEADTEK_VENDOR_ID, LEADTEK_9531_PRODUCT_ID) }, 81491b04ce1c9adfa0cd73f095086f3c37da81b667Dick Streefland { USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) }, 823b92847425a98d26ad9d2b8682d3ce6020c90752Matthew Meno { USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) }, 83b7aa94b682dc6b6dcdc01d36f8e65cef5aae81e2Kim Oldfield { USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) }, 848fd801339350b63cbb90730ff8b2be349fb3dc67Johannes Steingraeber { USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) }, 85b697f70f763fe92d5fd05e7e2043bd2b5f12b073Wesley PA { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_ID) }, 862d94b981c7fcb0fba4aa3442cd180066dbedbbc8YOSHIFUJI Hideaki { USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) }, 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { } /* Terminating entry */ 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 90372db8a780f63368c6960a167b7a19aad776d704Thiago GalesiMODULE_DEVICE_TABLE(usb, id_table); 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_driver pl2303_driver = { 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = "pl2303", 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .probe = usb_serial_probe, 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .disconnect = usb_serial_disconnect, 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id_table = id_table, 97ba9dc657af86d05d2971633e57d1f6f94ed60472Greg Kroah-Hartman .no_dynamic_id = 1, 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_LINE_REQUEST_TYPE 0x21 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_LINE_REQUEST 0x20 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_CONTROL_REQUEST_TYPE 0x21 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_CONTROL_REQUEST 0x22 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONTROL_DTR 0x01 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONTROL_RTS 0x02 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAK_REQUEST_TYPE 0x21 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAK_REQUEST 0x23 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAK_ON 0xffff 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAK_OFF 0x0000 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GET_LINE_REQUEST_TYPE 0xa1 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GET_LINE_REQUEST 0x21 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_WRITE_REQUEST_TYPE 0x40 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_WRITE_REQUEST 0x01 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_READ_REQUEST_TYPE 0xc0 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_READ_REQUEST 0x01 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_STATE 0x08 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_STATE_TRANSIENT_MASK 0x74 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_DCD 0x01 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_DSR 0x02 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_BREAK_ERROR 0x04 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_RING 0x08 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_FRAME_ERROR 0x10 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_PARITY_ERROR 0x20 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_OVERRUN_ERROR 0x40 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_CTS 0x80 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum pl2303_type { 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds type_0, /* don't know the difference between type 0 and */ 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds type_1, /* type 1, until someone from prolific tells us... */ 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HX, /* HX version of the pl2303 chip */ 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct pl2303_private { 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spinlock_t lock; 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pl2303_buf *buf; 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int write_urb_in_use; 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wait_queue_head_t delta_msr_wait; 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 line_control; 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 line_status; 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 termios_initialized; 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enum pl2303_type type; 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 151572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi/* 152572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * pl2303_buf_alloc 153572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * 154572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Allocate a circular buffer and all associated memory. 155572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi */ 156572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic struct pl2303_buf *pl2303_buf_alloc(unsigned int size) 157572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{ 158572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi struct pl2303_buf *pb; 159572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 160572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi if (size == 0) 161572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi return NULL; 162572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 1635cbded585d129d0226cb48ac4202b253c781be26Robert P. J. Day pb = kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL); 164572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi if (pb == NULL) 165572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi return NULL; 166572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 167572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi pb->buf_buf = kmalloc(size, GFP_KERNEL); 168572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi if (pb->buf_buf == NULL) { 169572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi kfree(pb); 170572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi return NULL; 171572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi } 172572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 173572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi pb->buf_size = size; 174572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi pb->buf_get = pb->buf_put = pb->buf_buf; 175572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 176572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi return pb; 177572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi} 178572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 179572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi/* 180572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * pl2303_buf_free 181572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * 182572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Free the buffer and all associated memory. 183572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi */ 184572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic void pl2303_buf_free(struct pl2303_buf *pb) 185572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{ 186572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi if (pb) { 187572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi kfree(pb->buf_buf); 188572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi kfree(pb); 189572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi } 190572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi} 191572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 192572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi/* 193572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * pl2303_buf_clear 194572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * 195572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Clear out all data in the circular buffer. 196572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi */ 197572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic void pl2303_buf_clear(struct pl2303_buf *pb) 198572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{ 199572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi if (pb != NULL) 200572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi pb->buf_get = pb->buf_put; 201572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi /* equivalent to a get of all data available */ 202572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi} 203572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 204572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi/* 205572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * pl2303_buf_data_avail 206572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * 207572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Return the number of bytes of data available in the circular 208572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * buffer. 209572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi */ 210572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb) 211572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{ 212572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi if (pb == NULL) 213572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi return 0; 214572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 215572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi return ((pb->buf_size + pb->buf_put - pb->buf_get) % pb->buf_size); 216572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi} 217572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 218572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi/* 219572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * pl2303_buf_space_avail 220572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * 221572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Return the number of bytes of space available in the circular 222572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * buffer. 223572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi */ 224572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb) 225572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{ 226572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi if (pb == NULL) 227572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi return 0; 228572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 229572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi return ((pb->buf_size + pb->buf_get - pb->buf_put - 1) % pb->buf_size); 230572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi} 231572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 232572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi/* 233572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * pl2303_buf_put 234572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * 235572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Copy data data from a user buffer and put it into the circular buffer. 236572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Restrict to the amount of space available. 237572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * 238572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Return the number of bytes copied. 239572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi */ 240572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf, 241572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi unsigned int count) 242572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{ 243572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi unsigned int len; 244572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 245572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi if (pb == NULL) 246572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi return 0; 247572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 248572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi len = pl2303_buf_space_avail(pb); 249572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi if (count > len) 250572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi count = len; 251572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 252572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi if (count == 0) 253572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi return 0; 254572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 255572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi len = pb->buf_buf + pb->buf_size - pb->buf_put; 256572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi if (count > len) { 257572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi memcpy(pb->buf_put, buf, len); 258572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi memcpy(pb->buf_buf, buf+len, count - len); 259572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi pb->buf_put = pb->buf_buf + count - len; 260572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi } else { 261572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi memcpy(pb->buf_put, buf, count); 262572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi if (count < len) 263572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi pb->buf_put += count; 264572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi else /* count == len */ 265572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi pb->buf_put = pb->buf_buf; 266572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi } 267572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 268572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi return count; 269572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi} 270572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 271572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi/* 272572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * pl2303_buf_get 273572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * 274572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Get data from the circular buffer and copy to the given buffer. 275572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Restrict to the amount of data available. 276572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * 277572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi * Return the number of bytes copied. 278572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi */ 279572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf, 280572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi unsigned int count) 281572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{ 282572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi unsigned int len; 283572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 284572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi if (pb == NULL) 285572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi return 0; 286572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 287572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi len = pl2303_buf_data_avail(pb); 288572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi if (count > len) 289572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi count = len; 290572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 291572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi if (count == 0) 292572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi return 0; 293572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 294572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi len = pb->buf_buf + pb->buf_size - pb->buf_get; 295572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi if (count > len) { 296572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi memcpy(buf, pb->buf_get, len); 297572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi memcpy(buf+len, pb->buf_buf, count - len); 298572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi pb->buf_get = pb->buf_buf + count - len; 299572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi } else { 300572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi memcpy(buf, pb->buf_get, count); 301572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi if (count < len) 302572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi pb->buf_get += count; 303572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi else /* count == len */ 304572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi pb->buf_get = pb->buf_buf; 305572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi } 306572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 307572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi return count; 308572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi} 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 310372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic int pl2303_startup(struct usb_serial *serial) 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pl2303_private *priv; 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enum pl2303_type type = type_0; 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (serial->dev->descriptor.bDeviceClass == 0x02) 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds type = type_0; 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40) 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds type = HX; 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (serial->dev->descriptor.bDeviceClass == 0x00) 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds type = type_1; 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (serial->dev->descriptor.bDeviceClass == 0xFF) 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds type = type_1; 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("device type: %d", type); 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < serial->num_ports; ++i) { 32780b6ca48321974a6566a1c9048ba34f60420bca6Eric Sesterhenn priv = kzalloc(sizeof(struct pl2303_private), GFP_KERNEL); 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!priv) 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto cleanup; 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_init(&priv->lock); 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->buf = pl2303_buf_alloc(PL2303_BUF_SIZE); 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (priv->buf == NULL) { 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(priv); 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto cleanup; 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_waitqueue_head(&priv->delta_msr_wait); 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->type = type; 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_set_serial_port_data(serial->port[i], priv); 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscleanup: 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (--i; i>=0; --i) { 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv = usb_get_serial_port_data(serial->port[i]); 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pl2303_buf_free(priv->buf); 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(priv); 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_set_serial_port_data(serial->port[i], NULL); 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 352372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic int set_control_lines(struct usb_device *dev, u8 value) 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 356372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 357372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE, 358372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi value, 0, NULL, 0, 100); 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - value = %d, retval = %d", __FUNCTION__, value, retval); 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pl2303_send(struct usb_serial_port *port) 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int count, result; 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pl2303_private *priv = usb_get_serial_port_data(port); 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - port %d", __FUNCTION__, port->number); 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&priv->lock, flags); 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (priv->write_urb_in_use) { 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count = pl2303_buf_get(priv->buf, port->write_urb->transfer_buffer, 379372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi port->bulk_out_size); 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (count == 0) { 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->write_urb_in_use = 1; 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 390372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, 391372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi port->write_urb->transfer_buffer); 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->write_urb->transfer_buffer_length = count; 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->write_urb->dev = port->serial->dev; 395372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi result = usb_submit_urb(port->write_urb, GFP_ATOMIC); 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) { 397372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi dev_err(&port->dev, "%s - failed submitting write urb," 398372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi " error %d\n", __FUNCTION__, result); 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->write_urb_in_use = 0; 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // TODO: reschedule pl2303_send 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 403cf2c7481d2ff7f0c266de873b2fe93883e9782f9Pete Zaitcev usb_serial_port_softint(port); 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 406572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic int pl2303_write(struct usb_serial_port *port, const unsigned char *buf, 407572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi int count) 408572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{ 409572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi struct pl2303_private *priv = usb_get_serial_port_data(port); 410572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi unsigned long flags; 411572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 412572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi dbg("%s - port %d, %d bytes", __FUNCTION__, port->number, count); 413572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 414572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi if (!count) 415572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi return count; 416572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 417572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi spin_lock_irqsave(&priv->lock, flags); 418572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi count = pl2303_buf_put(priv->buf, buf, count); 419572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi spin_unlock_irqrestore(&priv->lock, flags); 420572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 421572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi pl2303_send(port); 422572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 423572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi return count; 424572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi} 425572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pl2303_write_room(struct usb_serial_port *port) 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pl2303_private *priv = usb_get_serial_port_data(port); 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int room = 0; 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - port %d", __FUNCTION__, port->number); 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&priv->lock, flags); 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds room = pl2303_buf_space_avail(priv->buf); 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - returns %d", __FUNCTION__, room); 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return room; 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pl2303_chars_in_buffer(struct usb_serial_port *port) 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pl2303_private *priv = usb_get_serial_port_data(port); 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int chars = 0; 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - port %d", __FUNCTION__, port->number); 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&priv->lock, flags); 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds chars = pl2303_buf_data_avail(priv->buf); 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - returns %d", __FUNCTION__, chars); 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return chars; 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 458372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic void pl2303_set_termios(struct usb_serial_port *port, 459606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox struct ktermios *old_termios) 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_serial *serial = port->serial; 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pl2303_private *priv = usb_get_serial_port_data(port); 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int cflag; 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *buf; 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int baud; 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 control; 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - port %d", __FUNCTION__, port->number); 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((!port->tty) || (!port->tty->termios)) { 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - no tty structures", __FUNCTION__); 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&priv->lock, flags); 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!priv->termios_initialized) { 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *(port->tty->termios) = tty_std_termios; 480372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi port->tty->termios->c_cflag = B9600 | CS8 | CREAD | 481372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi HUPCL | CLOCAL; 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->termios_initialized = 1; 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cflag = port->tty->termios->c_cflag; 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* check that they really want us to change something */ 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (old_termios) { 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((cflag == old_termios->c_cflag) && 490372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi (RELEVANT_IFLAG(port->tty->termios->c_iflag) == 491372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi RELEVANT_IFLAG(old_termios->c_iflag))) { 492372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi dbg("%s - nothing to change...", __FUNCTION__); 493372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi return; 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 497372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi buf = kzalloc(7, GFP_KERNEL); 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!buf) { 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_err(&port->dev, "%s - out of memory.\n", __FUNCTION__); 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 503372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), 504372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE, 505372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi 0, 0, buf, 7, 100); 506372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i, 507372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cflag & CSIZE) { 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cflag & CSIZE) { 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CS5: buf[6] = 5; break; 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CS6: buf[6] = 6; break; 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CS7: buf[6] = 7; break; 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CS8: buf[6] = 8; break; 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - data bits = %d", __FUNCTION__, buf[6]); 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds baud = 0; 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cflag & CBAUD) { 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case B0: baud = 0; break; 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case B75: baud = 75; break; 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case B150: baud = 150; break; 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case B300: baud = 300; break; 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case B600: baud = 600; break; 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case B1200: baud = 1200; break; 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case B1800: baud = 1800; break; 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case B2400: baud = 2400; break; 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case B4800: baud = 4800; break; 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case B9600: baud = 9600; break; 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case B19200: baud = 19200; break; 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case B38400: baud = 38400; break; 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case B57600: baud = 57600; break; 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case B115200: baud = 115200; break; 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case B230400: baud = 230400; break; 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case B460800: baud = 460800; break; 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 539372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi dev_err(&port->dev, "pl2303 driver does not support" 540372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi " the baudrate requested (fix it)\n"); 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - baud = %d", __FUNCTION__, baud); 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (baud) { 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[0] = baud & 0xff; 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[1] = (baud >> 8) & 0xff; 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[2] = (baud >> 16) & 0xff; 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[3] = (baud >> 24) & 0xff; 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* For reference buf[4]=0 is 1 stop bits */ 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* For reference buf[4]=1 is 1.5 stop bits */ 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* For reference buf[4]=2 is 2 stop bits */ 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cflag & CSTOPB) { 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[4] = 2; 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - stop bits = 2", __FUNCTION__); 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[4] = 0; 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - stop bits = 1", __FUNCTION__); 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cflag & PARENB) { 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* For reference buf[5]=0 is none parity */ 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* For reference buf[5]=1 is odd parity */ 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* For reference buf[5]=2 is even parity */ 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* For reference buf[5]=3 is mark parity */ 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* For reference buf[5]=4 is space parity */ 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cflag & PARODD) { 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[5] = 1; 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - parity = odd", __FUNCTION__); 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[5] = 2; 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - parity = even", __FUNCTION__); 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[5] = 0; 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - parity = none", __FUNCTION__); 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 580372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 581372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE, 582372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi 0, 0, buf, 7, 100); 583372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi dbg("0x21:0x20:0:0 %d", i); 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* change control lines if we are switching to or from B0 */ 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&priv->lock, flags); 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds control = priv->line_control; 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((cflag & CBAUD) == B0) 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS); 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->line_control |= (CONTROL_DTR | CONTROL_RTS); 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (control != priv->line_control) { 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds control = priv->line_control; 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_control_lines(serial->dev, control); 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 599372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0; 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 602372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), 603372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE, 604372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi 0, 0, buf, 7, 100); 605372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i, 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cflag & CRTSCTS) { 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __u16 index; 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (priv->type == HX) 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds index = 0x61; 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds index = 0x41; 614372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi i = usb_control_msg(serial->dev, 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_sndctrlpipe(serial->dev, 0), 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VENDOR_WRITE_REQUEST, 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VENDOR_WRITE_REQUEST_TYPE, 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x0, index, NULL, 0, 100); 619372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi dbg("0x40:0x1:0x0:0x%x %d", index, i); 620715f9527c1c1edd1a9c7a55ab4535211279c9374t.sefzick } else { 621715f9527c1c1edd1a9c7a55ab4535211279c9374t.sefzick i = usb_control_msg(serial->dev, 622715f9527c1c1edd1a9c7a55ab4535211279c9374t.sefzick usb_sndctrlpipe(serial->dev, 0), 623715f9527c1c1edd1a9c7a55ab4535211279c9374t.sefzick VENDOR_WRITE_REQUEST, 624715f9527c1c1edd1a9c7a55ab4535211279c9374t.sefzick VENDOR_WRITE_REQUEST_TYPE, 625715f9527c1c1edd1a9c7a55ab4535211279c9374t.sefzick 0x0, 0x0, NULL, 0, 100); 626715f9527c1c1edd1a9c7a55ab4535211279c9374t.sefzick dbg ("0x40:0x1:0x0:0x0 %d", i); 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 628572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 629572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi kfree(buf); 630572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi} 631572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 632572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic void pl2303_close(struct usb_serial_port *port, struct file *filp) 633572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{ 634572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi struct pl2303_private *priv = usb_get_serial_port_data(port); 635572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi unsigned long flags; 636572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi unsigned int c_cflag; 637572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi int bps; 638572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi long timeout; 639572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi wait_queue_t wait; 640572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 641572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi dbg("%s - port %d", __FUNCTION__, port->number); 642572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 643572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi /* wait for data to drain from the buffer */ 644572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi spin_lock_irqsave(&priv->lock, flags); 645572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi timeout = PL2303_CLOSING_WAIT; 646572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi init_waitqueue_entry(&wait, current); 647572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi add_wait_queue(&port->tty->write_wait, &wait); 648572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi for (;;) { 649572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi set_current_state(TASK_INTERRUPTIBLE); 650572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi if (pl2303_buf_data_avail(priv->buf) == 0 || 651572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi timeout == 0 || signal_pending(current) || 652572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi !usb_get_intfdata(port->serial->interface)) /* disconnect */ 653572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi break; 654572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi spin_unlock_irqrestore(&priv->lock, flags); 655572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi timeout = schedule_timeout(timeout); 656572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi spin_lock_irqsave(&priv->lock, flags); 657572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi } 658572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi set_current_state(TASK_RUNNING); 659572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi remove_wait_queue(&port->tty->write_wait, &wait); 660572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi /* clear out any remaining data in the buffer */ 661572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi pl2303_buf_clear(priv->buf); 662572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi spin_unlock_irqrestore(&priv->lock, flags); 663572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 664572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi /* wait for characters to drain from the device */ 665572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi /* (this is long enough for the entire 256 byte */ 666572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi /* pl2303 hardware buffer to drain with no flow */ 667572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi /* control for data rates of 1200 bps or more, */ 668572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi /* for lower rates we should really know how much */ 669572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi /* data is in the buffer to compute a delay */ 670572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi /* that is not unnecessarily long) */ 671572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi bps = tty_get_baud_rate(port->tty); 672572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi if (bps > 1200) 673572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi timeout = max((HZ*2560)/bps,HZ/10); 674572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi else 675572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi timeout = 2*HZ; 676572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi schedule_timeout_interruptible(timeout); 677572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 678572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi /* shutdown our urbs */ 679572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi dbg("%s - shutting down urbs", __FUNCTION__); 680572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi usb_kill_urb(port->write_urb); 681572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi usb_kill_urb(port->read_urb); 682572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi usb_kill_urb(port->interrupt_in_urb); 683572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 684572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi if (port->tty) { 685572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi c_cflag = port->tty->termios->c_cflag; 686572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi if (c_cflag & HUPCL) { 687572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi /* drop DTR and RTS */ 688572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi spin_lock_irqsave(&priv->lock, flags); 689572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi priv->line_control = 0; 690572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi spin_unlock_irqrestore(&priv->lock, flags); 691572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi set_control_lines(port->serial->dev, 0); 692572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi } 693572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi } 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 696372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic int pl2303_open(struct usb_serial_port *port, struct file *filp) 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 698606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox struct ktermios tmp_termios; 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_serial *serial = port->serial; 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pl2303_private *priv = usb_get_serial_port_data(port); 7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *buf; 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result; 7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - port %d", __FUNCTION__, port->number); 7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7061694899fd1af43636351aac97f415fd3c9cefb1dDariusz M if (priv->type != HX) { 7071694899fd1af43636351aac97f415fd3c9cefb1dDariusz M usb_clear_halt(serial->dev, port->write_urb->pipe); 7081694899fd1af43636351aac97f415fd3c9cefb1dDariusz M usb_clear_halt(serial->dev, port->read_urb->pipe); 7091694899fd1af43636351aac97f415fd3c9cefb1dDariusz M } 7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf = kmalloc(10, GFP_KERNEL); 7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (buf==NULL) 7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FISH(a,b,c,d) \ 7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result=usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev,0), \ 7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds b, a, c, d, buf, 1, 100); \ 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("0x%x:0x%x:0x%x:0x%x %d - %x",a,b,c,d,result,buf[0]); 7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SOUP(a,b,c,d) \ 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result=usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev,0), \ 7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds b, a, c, d, NULL, 0, 100); \ 7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("0x%x:0x%x:0x%x:0x%x %d",a,b,c,d,result); 7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0); 7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0x0404, 0); 7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0); 7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0); 7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0); 7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0x0404, 1); 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0); 7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0); 7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0, 1); 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 1, 0); 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (priv->type == HX) { 7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* HX chip */ 7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 2, 0x44); 7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* reset upstream data pipes */ 7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 8, 0); 7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 9, 0); 7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 2, 0x24); 7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(buf); 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Setup termios */ 7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (port->tty) { 750372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi pl2303_set_termios(port, &tmp_termios); 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds //FIXME: need to assert RTS and DTR if CRTSCTS off 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - submitting read urb", __FUNCTION__); 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->read_urb->dev = serial->dev; 757372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi result = usb_submit_urb(port->read_urb, GFP_KERNEL); 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) { 759372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi dev_err(&port->dev, "%s - failed submitting read urb," 760372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi " error %d\n", __FUNCTION__, result); 761372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi pl2303_close(port, NULL); 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EPROTO; 7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - submitting interrupt urb", __FUNCTION__); 7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->interrupt_in_urb->dev = serial->dev; 767372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); 7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) { 769372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi dev_err(&port->dev, "%s - failed submitting interrupt urb," 770372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi " error %d\n", __FUNCTION__, result); 771372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi pl2303_close(port, NULL); 7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EPROTO; 7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 777372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic int pl2303_tiocmset(struct usb_serial_port *port, struct file *file, 778372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi unsigned int set, unsigned int clear) 7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pl2303_private *priv = usb_get_serial_port_data(port); 7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 control; 7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7846fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner if (!usb_get_intfdata(port->serial->interface)) 7856fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner return -ENODEV; 7866fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner 787372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi spin_lock_irqsave(&priv->lock, flags); 7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (set & TIOCM_RTS) 7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->line_control |= CONTROL_RTS; 7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (set & TIOCM_DTR) 7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->line_control |= CONTROL_DTR; 7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (clear & TIOCM_RTS) 7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->line_control &= ~CONTROL_RTS; 7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (clear & TIOCM_DTR) 7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->line_control &= ~CONTROL_DTR; 7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds control = priv->line_control; 797372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi spin_unlock_irqrestore(&priv->lock, flags); 7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 799372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi return set_control_lines(port->serial->dev, control); 8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 802372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic int pl2303_tiocmget(struct usb_serial_port *port, struct file *file) 8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pl2303_private *priv = usb_get_serial_port_data(port); 8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int mcr; 8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int status; 8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int result; 8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s (%d)", __FUNCTION__, port->number); 8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8126fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner if (!usb_get_intfdata(port->serial->interface)) 8136fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner return -ENODEV; 8146fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner 815372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi spin_lock_irqsave(&priv->lock, flags); 8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mcr = priv->line_control; 8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = priv->line_status; 818372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi spin_unlock_irqrestore(&priv->lock, flags); 8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = ((mcr & CONTROL_DTR) ? TIOCM_DTR : 0) 8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | ((mcr & CONTROL_RTS) ? TIOCM_RTS : 0) 8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | ((status & UART_CTS) ? TIOCM_CTS : 0) 8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | ((status & UART_DSR) ? TIOCM_DSR : 0) 8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | ((status & UART_RING) ? TIOCM_RI : 0) 8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | ((status & UART_DCD) ? TIOCM_CD : 0); 8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - result = %x", __FUNCTION__, result); 8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return result; 8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int wait_modem_info(struct usb_serial_port *port, unsigned int arg) 8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pl2303_private *priv = usb_get_serial_port_data(port); 8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int prevstatus; 8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int status; 8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int changed; 8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 840372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi spin_lock_irqsave(&priv->lock, flags); 8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds prevstatus = priv->line_status; 842372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi spin_unlock_irqrestore(&priv->lock, flags); 8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (1) { 8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds interruptible_sleep_on(&priv->delta_msr_wait); 8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* see if a signal did it */ 8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (signal_pending(current)) 8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ERESTARTSYS; 849372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi 850372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi spin_lock_irqsave(&priv->lock, flags); 8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = priv->line_status; 852372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi spin_unlock_irqrestore(&priv->lock, flags); 853372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi 8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds changed=prevstatus^status; 855372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi 8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (((arg & TIOCM_RNG) && (changed & UART_RING)) || 8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((arg & TIOCM_DSR) && (changed & UART_DSR)) || 8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((arg & TIOCM_CD) && (changed & UART_DCD)) || 8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((arg & TIOCM_CTS) && (changed & UART_CTS)) ) { 8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds prevstatus = status; 8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* NOTREACHED */ 8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 868372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic int pl2303_ioctl(struct usb_serial_port *port, struct file *file, 869372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi unsigned int cmd, unsigned long arg) 8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s (%d) cmd = 0x%04x", __FUNCTION__, port->number, cmd); 8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cmd) { 8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case TIOCMIWAIT: 8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s (%d) TIOCMIWAIT", __FUNCTION__, port->number); 8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return wait_modem_info(port, arg); 8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s not supported = 0x%04x", __FUNCTION__, cmd); 8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOIOCTLCMD; 8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 886372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic void pl2303_break_ctl(struct usb_serial_port *port, int break_state) 8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_serial *serial = port->serial; 8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 state; 8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result; 8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - port %d", __FUNCTION__, port->number); 8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (break_state == 0) 8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds state = BREAK_OFF; 8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds state = BREAK_ON; 8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - turning break %s", __FUNCTION__, state==BREAK_OFF ? "off" : "on"); 8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 900372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 901372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi BREAK_REQUEST, BREAK_REQUEST_TYPE, state, 902372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi 0, NULL, 0, 100); 9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) 9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - error sending break = %d", __FUNCTION__, result); 9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 907372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic void pl2303_shutdown(struct usb_serial *serial) 9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pl2303_private *priv; 9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s", __FUNCTION__); 9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < serial->num_ports; ++i) { 9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv = usb_get_serial_port_data(serial->port[i]); 9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (priv) { 9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pl2303_buf_free(priv->buf); 9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(priv); 9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_set_serial_port_data(serial->port[i], NULL); 9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 921372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi } 9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 92497bb13ec5bc156352cca8af90080597e04299a73Flavio Leitnerstatic void pl2303_update_line_status(struct usb_serial_port *port, 92597bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner unsigned char *data, 92697bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner unsigned int actual_length) 92797bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner{ 92897bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner 92997bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner struct pl2303_private *priv = usb_get_serial_port_data(port); 93097bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner unsigned long flags; 93197bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner u8 status_idx = UART_STATE; 93295f209f93663103db2a8fb989e226ac68a98b036Horst Schirmeier u8 length = UART_STATE + 1; 9339c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi u16 idv, idp; 93497bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner 9359c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi idv = le16_to_cpu(port->serial->dev->descriptor.idVendor); 9369c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi idp = le16_to_cpu(port->serial->dev->descriptor.idProduct); 9379c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi 9389c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi 9399c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi if (idv == SIEMENS_VENDOR_ID) { 9409c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi if (idp == SIEMENS_PRODUCT_ID_X65 || 9419c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi idp == SIEMENS_PRODUCT_ID_SX1 || 9429c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi idp == SIEMENS_PRODUCT_ID_X75) { 9439c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi 9449c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi length = 1; 9459c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi status_idx = 0; 9469c53761681497d598a31ed2f6b29b5b3480c49dbThiago Galesi } 94797bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner } 94897bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner 94997bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner if (actual_length < length) 950a009b75aa0ed55f0bc473c8a3b3e872cbca807ecLuiz Fernando N. Capitulino return; 95197bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner 95297bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner /* Save off the uart status for others to look at */ 95397bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner spin_lock_irqsave(&priv->lock, flags); 95497bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner priv->line_status = data[status_idx]; 95597bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner spin_unlock_irqrestore(&priv->lock, flags); 956372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi wake_up_interruptible(&priv->delta_msr_wait); 95797bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner} 9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9597d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void pl2303_read_int_callback(struct urb *urb) 9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_serial_port *port = (struct usb_serial_port *) urb->context; 9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *data = urb->transfer_buffer; 96397bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner unsigned int actual_length = urb->actual_length; 964461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman int status = urb->status; 965461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman int retval; 9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s (%d)", __FUNCTION__, port->number); 9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 969461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman switch (status) { 9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0: 9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* success */ 9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -ECONNRESET: 9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -ENOENT: 9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -ESHUTDOWN: 9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* this urb is terminated, clean up */ 977372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi dbg("%s - urb shutting down with status: %d", __FUNCTION__, 978461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman status); 9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 981372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi dbg("%s - nonzero urb status received: %d", __FUNCTION__, 982461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman status); 9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 986372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi usb_serial_debug_data(debug, &port->dev, __FUNCTION__, 987372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi urb->actual_length, urb->transfer_buffer); 988372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi 98997bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner pl2303_update_line_status(port, data, actual_length); 9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit: 992461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman retval = usb_submit_urb(urb, GFP_ATOMIC); 993461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman if (retval) 994372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi dev_err(&urb->dev->dev, 995372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi "%s - usb_submit_urb failed with result %d\n", 996461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman __FUNCTION__, retval); 9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9997d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void pl2303_read_bulk_callback(struct urb *urb) 10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_serial_port *port = (struct usb_serial_port *) urb->context; 10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pl2303_private *priv = usb_get_serial_port_data(port); 10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct tty_struct *tty; 10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *data = urb->transfer_buffer; 10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result; 1008461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman int status = urb->status; 1009461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman u8 line_status; 10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char tty_flag; 10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - port %d", __FUNCTION__, port->number); 10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1014461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman if (status) { 1015461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman dbg("%s - urb status = %d", __FUNCTION__, status); 10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!port->open_count) { 10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - port is closed, exiting.", __FUNCTION__); 10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1020461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman if (status == -EPROTO) { 1021372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi /* PL2303 mysteriously fails with -EPROTO reschedule 1022372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi * the read */ 1023372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi dbg("%s - caught -EPROTO, resubmitting the urb", 1024372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi __FUNCTION__); 10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb->dev = port->serial->dev; 10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = usb_submit_urb(urb, GFP_ATOMIC); 10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) 1028372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi dev_err(&urb->dev->dev, "%s - failed" 1029372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi " resubmitting read urb, error %d\n", 1030372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi __FUNCTION__, result); 10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - unable to handle the error, exiting.", __FUNCTION__); 10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1037372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi usb_serial_debug_data(debug, &port->dev, __FUNCTION__, 1038372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi urb->actual_length, data); 10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* get tty_flag from status */ 10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty_flag = TTY_NORMAL; 10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&priv->lock, flags); 1044461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman line_status = priv->line_status; 10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->line_status &= ~UART_STATE_TRANSIENT_MASK; 10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 1047372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi wake_up_interruptible(&priv->delta_msr_wait); 10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* break takes precedence over parity, */ 10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* which takes precedence over framing errors */ 1051461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman if (line_status & UART_BREAK_ERROR ) 10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty_flag = TTY_BREAK; 1053461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman else if (line_status & UART_PARITY_ERROR) 10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty_flag = TTY_PARITY; 1055461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman else if (line_status & UART_FRAME_ERROR) 10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty_flag = TTY_FRAME; 10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - tty_flag = %d", __FUNCTION__, tty_flag); 10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty = port->tty; 10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tty && urb->actual_length) { 106133f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox tty_buffer_request_room(tty, urb->actual_length + 1); 10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* overrun is special, not associated with a char */ 1063461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman if (line_status & UART_OVERRUN_ERROR) 10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty_insert_flip_char(tty, 0, TTY_OVERRUN); 106533f0f88f1c51ae5c2d593d26960c760ea154c2e2Alan Cox for (i = 0; i < urb->actual_length; ++i) 1066372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi tty_insert_flip_char(tty, data[i], tty_flag); 1067372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi tty_flip_buffer_push(tty); 10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Schedule the next read _if_ we are still open */ 10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (port->open_count) { 10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb->dev = port->serial->dev; 10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = usb_submit_urb(urb, GFP_ATOMIC); 10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) 1075372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi dev_err(&urb->dev->dev, "%s - failed resubmitting" 1076372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi " read urb, error %d\n", __FUNCTION__, result); 10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10827d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void pl2303_write_bulk_callback(struct urb *urb) 10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_serial_port *port = (struct usb_serial_port *) urb->context; 10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pl2303_private *priv = usb_get_serial_port_data(port); 10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result; 1087461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman int status = urb->status; 10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - port %d", __FUNCTION__, port->number); 10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1091461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman switch (status) { 10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0: 10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* success */ 10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -ECONNRESET: 10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -ENOENT: 10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -ESHUTDOWN: 10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* this urb is terminated, clean up */ 1099372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi dbg("%s - urb shutting down with status: %d", __FUNCTION__, 1100461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman status); 11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->write_urb_in_use = 0; 11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* error in the urb, so we have to resubmit it */ 11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - Overflow in write", __FUNCTION__); 1106372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, 1107461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman status); 11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->write_urb->transfer_buffer_length = 1; 11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->write_urb->dev = port->serial->dev; 1110372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi result = usb_submit_urb(port->write_urb, GFP_ATOMIC); 11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) 1112372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi dev_err(&urb->dev->dev, "%s - failed resubmitting write" 1113372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi " urb, error %d\n", __FUNCTION__, result); 11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->write_urb_in_use = 0; 11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* send any buffered data */ 11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pl2303_send(port); 11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1124572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi/* All of the device info needed for the PL2303 SIO serial converter */ 1125572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic struct usb_serial_driver pl2303_device = { 1126572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .driver = { 1127572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .owner = THIS_MODULE, 1128572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .name = "pl2303", 1129572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi }, 1130572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .id_table = id_table, 1131d9b1b787736852f462dbf277b3ca708cbbf693aeJohannes Hölzl .usb_driver = &pl2303_driver, 1132572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .num_interrupt_in = NUM_DONT_CARE, 1133572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .num_bulk_in = 1, 1134572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .num_bulk_out = 1, 1135572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .num_ports = 1, 1136572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .open = pl2303_open, 1137572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .close = pl2303_close, 1138572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .write = pl2303_write, 1139572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .ioctl = pl2303_ioctl, 1140572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .break_ctl = pl2303_break_ctl, 1141572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .set_termios = pl2303_set_termios, 1142572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .tiocmget = pl2303_tiocmget, 1143572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .tiocmset = pl2303_tiocmset, 1144572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .read_bulk_callback = pl2303_read_bulk_callback, 1145572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .read_int_callback = pl2303_read_int_callback, 1146572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .write_bulk_callback = pl2303_write_bulk_callback, 1147572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .write_room = pl2303_write_room, 1148572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .chars_in_buffer = pl2303_chars_in_buffer, 1149572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .attach = pl2303_startup, 1150572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .shutdown = pl2303_shutdown, 1151572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi}; 11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1153372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic int __init pl2303_init(void) 11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 1156372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi 11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = usb_serial_register(&pl2303_device); 11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) 11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto failed_usb_serial_register; 11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = usb_register(&pl2303_driver); 11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) 11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto failed_usb_register; 116317a882fc0c91477b2582a6dfd4ca93ae7eb58cd3Greg Kroah-Hartman info(DRIVER_DESC); 11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfailed_usb_register: 11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_serial_deregister(&pl2303_device); 11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfailed_usb_serial_register: 11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1171372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic void __exit pl2303_exit(void) 11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1173372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi usb_deregister(&pl2303_driver); 1174372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi usb_serial_deregister(&pl2303_device); 11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(pl2303_init); 11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(pl2303_exit); 11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION(DRIVER_DESC); 11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(debug, bool, S_IRUGO | S_IWUSR); 11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(debug, "Debug enabled or not"); 11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1186