11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * USB Cypress M8 driver 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2004 5813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox * Lonnie Mendez (dignome@gmail.com) 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2003,2004 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Neil Whelchel (koyama@firstlight.net) 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License as published by 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the Free Software Foundation; either version 2 of the License, or 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (at your option) any later version. 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 14813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox * See Documentation/usb/usb-serial.txt for more information on using this 15813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox * driver 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * See http://geocities.com/i0xox0i for information on this driver and the 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * earthmate usb device. 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox/* Thanks to Neil Whelchel for writing the first cypress m8 implementation 22813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox for linux. */ 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Thanks to cypress for providing references for the hid reports. */ 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Thanks to Jiang Zhang for providing links and for general help. */ 25813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox/* Code originates and was built up from ftdi_sio, belkin, pl2303 and others.*/ 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty.h> 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty_driver.h> 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty_flip.h> 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/moduleparam.h> 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h> 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/usb.h> 39a969888ce91673c7f4b86520d851a6f0d5a5fa7dGreg Kroah-Hartman#include <linux/usb/serial.h> 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/serial.h> 41117fb8d086cfc6e51c729fe5533bb83cb55c150aJohan Hovold#include <linux/kfifo.h> 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h> 43813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox#include <linux/uaccess.h> 440f2c2d7bbb51338fdcda9670795a6c6e348622d9Johan Hovold#include <asm/unaligned.h> 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "cypress_m8.h" 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4990ab5ee94171b3e28de6bb42ee30b527014e0be7Rusty Russellstatic bool debug; 5090ab5ee94171b3e28de6bb42ee30b527014e0be7Rusty Russellstatic bool stats; 513cb4a4f739cccdf0642fa7e3a087e0b8425ff67bLonnie Mendezstatic int interval; 5290ab5ee94171b3e28de6bb42ee30b527014e0be7Rusty Russellstatic bool unstable_bauds; 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Version Information 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 57117fb8d086cfc6e51c729fe5533bb83cb55c150aJohan Hovold#define DRIVER_VERSION "v1.10" 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_AUTHOR "Lonnie Mendez <dignome@gmail.com>, Neil Whelchel <koyama@firstlight.net>" 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_DESC "Cypress USB to Serial Driver" 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* write buffer size defines */ 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CYPRESS_BUF_SIZE 1024 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 647d40d7e85a25e01948bcb4dc3eda1355af318337Németh Mártonstatic const struct usb_device_id id_table_earthmate[] = { 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB) }, 6625b6f08e3fa0d84e26a373a205cfdad208b54af7Lonnie Mendez { USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB_LT20) }, 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { } /* Terminating entry */ 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 707d40d7e85a25e01948bcb4dc3eda1355af318337Németh Mártonstatic const struct usb_device_id id_table_cyphidcomrs232[] = { 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(VENDOR_ID_CYPRESS, PRODUCT_ID_CYPHIDCOM) }, 726f6f06ee6ada13b0fb39c800f8567ff81d4e807dDmitry Shapin { USB_DEVICE(VENDOR_ID_POWERCOM, PRODUCT_ID_UPS) }, 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { } /* Terminating entry */ 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 767d40d7e85a25e01948bcb4dc3eda1355af318337Németh Mártonstatic const struct usb_device_id id_table_nokiaca42v2[] = { 77a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez { USB_DEVICE(VENDOR_ID_DAZZLE, PRODUCT_ID_CA42) }, 78a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez { } /* Terminating entry */ 79a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez}; 80a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez 817d40d7e85a25e01948bcb4dc3eda1355af318337Németh Mártonstatic const struct usb_device_id id_table_combined[] = { 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB) }, 8325b6f08e3fa0d84e26a373a205cfdad208b54af7Lonnie Mendez { USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB_LT20) }, 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(VENDOR_ID_CYPRESS, PRODUCT_ID_CYPHIDCOM) }, 856f6f06ee6ada13b0fb39c800f8567ff81d4e807dDmitry Shapin { USB_DEVICE(VENDOR_ID_POWERCOM, PRODUCT_ID_UPS) }, 86a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez { USB_DEVICE(VENDOR_ID_DAZZLE, PRODUCT_ID_CA42) }, 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { } /* Terminating entry */ 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 90813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan CoxMODULE_DEVICE_TABLE(usb, id_table_combined); 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_driver cypress_driver = { 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = "cypress", 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .probe = usb_serial_probe, 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .disconnect = usb_serial_disconnect, 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id_table = id_table_combined, 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 993416eaa1f8f8d516b77de514e14cf8da256d28fbMike Iselyenum packet_format { 1003416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely packet_format_1, /* b0:status, b1:payload count */ 1013416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely packet_format_2 /* b0[7:3]:status, b0[2:0]:payload count */ 1023416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely}; 1033416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct cypress_private { 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spinlock_t lock; /* private lock */ 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int chiptype; /* identifier of device, for quirks/etc */ 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int bytes_in; /* used for statistics */ 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int bytes_out; /* used for statistics */ 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int cmd_count; /* used for statistics */ 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int cmd_ctrl; /* always set this to 1 before issuing a command */ 111117fb8d086cfc6e51c729fe5533bb83cb55c150aJohan Hovold struct kfifo write_fifo; /* write fifo */ 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int write_urb_in_use; /* write urb in use indicator */ 1130257fa9ffe4f0287a9d90476bb733cfc2272396eMike Isely int write_urb_interval; /* interval to use for write urb */ 1140257fa9ffe4f0287a9d90476bb733cfc2272396eMike Isely int read_urb_interval; /* interval to use for read urb */ 11578aef519ed07797f94cff1d0d66dd01704474916Mike Isely int comm_is_ok; /* true if communication is (still) ok */ 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int termios_initialized; 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __u8 line_control; /* holds dtr / rts value */ 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __u8 current_status; /* received from last read - info on dsr,cts,cd,ri,etc */ 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __u8 current_config; /* stores the current configuration byte */ 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __u8 rx_flags; /* throttling - used from whiteheat/ftdi_sio */ 1213416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely enum packet_format pkt_fmt; /* format to use for packet send / receive */ 1223d6aa3206540e1e68bda9e8ea11ec71444f1ac71Mike Isely int get_cfg_unsafe; /* If true, the CYPRESS_GET_CONFIG is unsafe */ 123813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox int baud_rate; /* stores current baud rate in 124813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox integer form */ 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int isthrottled; /* if throttled, discard reads */ 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wait_queue_head_t delta_msr_wait; /* used for TIOCMIWAIT */ 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char prev_status, diff_status; /* used for TIOCMIWAIT */ 1283ad2f3fbb961429d2aa627465ae4829758bc7e07Daniel Mack /* we pass a pointer to this as the argument sent to 129813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox cypress_set_termios old_termios */ 130606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox struct ktermios tmp_termios; /* stores the old termios settings */ 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* function prototypes for the Cypress USB to serial device */ 134813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Coxstatic int cypress_earthmate_startup(struct usb_serial *serial); 135813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Coxstatic int cypress_hidcom_startup(struct usb_serial *serial); 136813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Coxstatic int cypress_ca42v2_startup(struct usb_serial *serial); 137f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Sternstatic void cypress_release(struct usb_serial *serial); 138a509a7e478e4766114d69f12d19d644ac63e9765Alan Coxstatic int cypress_open(struct tty_struct *tty, struct usb_serial_port *port); 139335f8514f200e63d689113d29cb7253a5c282967Alan Coxstatic void cypress_close(struct usb_serial_port *port); 140335f8514f200e63d689113d29cb7253a5c282967Alan Coxstatic void cypress_dtr_rts(struct usb_serial_port *port, int on); 141813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Coxstatic int cypress_write(struct tty_struct *tty, struct usb_serial_port *port, 142813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox const unsigned char *buf, int count); 143813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Coxstatic void cypress_send(struct usb_serial_port *port); 144813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Coxstatic int cypress_write_room(struct tty_struct *tty); 14500a0d0d65b61241a718d0aee96f46b9a2d93bf26Alan Coxstatic int cypress_ioctl(struct tty_struct *tty, 146813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox unsigned int cmd, unsigned long arg); 147813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Coxstatic void cypress_set_termios(struct tty_struct *tty, 148813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox struct usb_serial_port *port, struct ktermios *old); 14960b33c133ca0b7c0b6072c87234b63fee6e80558Alan Coxstatic int cypress_tiocmget(struct tty_struct *tty); 15020b9d17715017ae4dd4ec87fabc36d33b9de708eAlan Coxstatic int cypress_tiocmset(struct tty_struct *tty, 151813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox unsigned int set, unsigned int clear); 152813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Coxstatic int cypress_chars_in_buffer(struct tty_struct *tty); 153813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Coxstatic void cypress_throttle(struct tty_struct *tty); 154813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Coxstatic void cypress_unthrottle(struct tty_struct *tty); 155813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Coxstatic void cypress_set_dead(struct usb_serial_port *port); 156813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Coxstatic void cypress_read_int_callback(struct urb *urb); 157813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Coxstatic void cypress_write_int_callback(struct urb *urb); 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 159ea65370d025f5005649e5cb37c4d025e92c6fc38Greg Kroah-Hartmanstatic struct usb_serial_driver cypress_earthmate_device = { 16018fcac353fdc7cd072b0d24c8667042e675a4c11Greg Kroah-Hartman .driver = { 16118fcac353fdc7cd072b0d24c8667042e675a4c11Greg Kroah-Hartman .owner = THIS_MODULE, 162269bda1c123c7caf88e1deb2264f9086f0344192Greg Kroah-Hartman .name = "earthmate", 16318fcac353fdc7cd072b0d24c8667042e675a4c11Greg Kroah-Hartman }, 164269bda1c123c7caf88e1deb2264f9086f0344192Greg Kroah-Hartman .description = "DeLorme Earthmate USB", 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id_table = id_table_earthmate, 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .num_ports = 1, 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .attach = cypress_earthmate_startup, 168f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Stern .release = cypress_release, 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .open = cypress_open, 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .close = cypress_close, 171335f8514f200e63d689113d29cb7253a5c282967Alan Cox .dtr_rts = cypress_dtr_rts, 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write = cypress_write, 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write_room = cypress_write_room, 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .ioctl = cypress_ioctl, 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .set_termios = cypress_set_termios, 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .tiocmget = cypress_tiocmget, 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .tiocmset = cypress_tiocmset, 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .chars_in_buffer = cypress_chars_in_buffer, 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .throttle = cypress_throttle, 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .unthrottle = cypress_unthrottle, 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .read_int_callback = cypress_read_int_callback, 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write_int_callback = cypress_write_int_callback, 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 185ea65370d025f5005649e5cb37c4d025e92c6fc38Greg Kroah-Hartmanstatic struct usb_serial_driver cypress_hidcom_device = { 18618fcac353fdc7cd072b0d24c8667042e675a4c11Greg Kroah-Hartman .driver = { 18718fcac353fdc7cd072b0d24c8667042e675a4c11Greg Kroah-Hartman .owner = THIS_MODULE, 188269bda1c123c7caf88e1deb2264f9086f0344192Greg Kroah-Hartman .name = "cyphidcom", 18918fcac353fdc7cd072b0d24c8667042e675a4c11Greg Kroah-Hartman }, 190269bda1c123c7caf88e1deb2264f9086f0344192Greg Kroah-Hartman .description = "HID->COM RS232 Adapter", 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id_table = id_table_cyphidcomrs232, 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .num_ports = 1, 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .attach = cypress_hidcom_startup, 194f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Stern .release = cypress_release, 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .open = cypress_open, 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .close = cypress_close, 197335f8514f200e63d689113d29cb7253a5c282967Alan Cox .dtr_rts = cypress_dtr_rts, 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write = cypress_write, 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write_room = cypress_write_room, 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .ioctl = cypress_ioctl, 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .set_termios = cypress_set_termios, 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .tiocmget = cypress_tiocmget, 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .tiocmset = cypress_tiocmset, 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .chars_in_buffer = cypress_chars_in_buffer, 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .throttle = cypress_throttle, 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .unthrottle = cypress_unthrottle, 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .read_int_callback = cypress_read_int_callback, 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write_int_callback = cypress_write_int_callback, 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 211a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendezstatic struct usb_serial_driver cypress_ca42v2_device = { 212a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez .driver = { 213a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez .owner = THIS_MODULE, 214813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox .name = "nokiaca42v2", 215a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez }, 216a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez .description = "Nokia CA-42 V2 Adapter", 217a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez .id_table = id_table_nokiaca42v2, 218a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez .num_ports = 1, 219a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez .attach = cypress_ca42v2_startup, 220f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Stern .release = cypress_release, 221a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez .open = cypress_open, 222a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez .close = cypress_close, 223335f8514f200e63d689113d29cb7253a5c282967Alan Cox .dtr_rts = cypress_dtr_rts, 224a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez .write = cypress_write, 225a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez .write_room = cypress_write_room, 226a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez .ioctl = cypress_ioctl, 227a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez .set_termios = cypress_set_termios, 228a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez .tiocmget = cypress_tiocmget, 229a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez .tiocmset = cypress_tiocmset, 230a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez .chars_in_buffer = cypress_chars_in_buffer, 231a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez .throttle = cypress_throttle, 232a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez .unthrottle = cypress_unthrottle, 233a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez .read_int_callback = cypress_read_int_callback, 234a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez .write_int_callback = cypress_write_int_callback, 235a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez}; 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23708a4f6bc2e7046ce50849d7589b7d0763926d808Alan Sternstatic struct usb_serial_driver * const serial_drivers[] = { 23808a4f6bc2e7046ce50849d7589b7d0763926d808Alan Stern &cypress_earthmate_device, &cypress_hidcom_device, 23908a4f6bc2e7046ce50849d7589b7d0763926d808Alan Stern &cypress_ca42v2_device, NULL 24008a4f6bc2e7046ce50849d7589b7d0763926d808Alan Stern}; 24108a4f6bc2e7046ce50849d7589b7d0763926d808Alan Stern 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/***************************************************************************** 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Cypress serial helper functions 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *****************************************************************************/ 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2478873aaa6e574d85c020a1c472d6d159cd1ec8aefAlan Coxstatic int analyze_baud_rate(struct usb_serial_port *port, speed_t new_rate) 24892983c2121fb46f234add1c36b5e596779899d56Mike Isely{ 24992983c2121fb46f234add1c36b5e596779899d56Mike Isely struct cypress_private *priv; 25092983c2121fb46f234add1c36b5e596779899d56Mike Isely priv = usb_get_serial_port_data(port); 25192983c2121fb46f234add1c36b5e596779899d56Mike Isely 252c312659c5ff1e54bac2d91e1ce1005d58784a7b5Mike Frysinger if (unstable_bauds) 253c312659c5ff1e54bac2d91e1ce1005d58784a7b5Mike Frysinger return new_rate; 254c312659c5ff1e54bac2d91e1ce1005d58784a7b5Mike Frysinger 25592983c2121fb46f234add1c36b5e596779899d56Mike Isely /* 25692983c2121fb46f234add1c36b5e596779899d56Mike Isely * The general purpose firmware for the Cypress M8 allows for 25792983c2121fb46f234add1c36b5e596779899d56Mike Isely * a maximum speed of 57600bps (I have no idea whether DeLorme 25892983c2121fb46f234add1c36b5e596779899d56Mike Isely * chose to use the general purpose firmware or not), if you 25992983c2121fb46f234add1c36b5e596779899d56Mike Isely * need to modify this speed setting for your own project 26092983c2121fb46f234add1c36b5e596779899d56Mike Isely * please add your own chiptype and modify the code likewise. 26192983c2121fb46f234add1c36b5e596779899d56Mike Isely * The Cypress HID->COM device will work successfully up to 26292983c2121fb46f234add1c36b5e596779899d56Mike Isely * 115200bps (but the actual throughput is around 3kBps). 26392983c2121fb46f234add1c36b5e596779899d56Mike Isely */ 26492983c2121fb46f234add1c36b5e596779899d56Mike Isely if (port->serial->dev->speed == USB_SPEED_LOW) { 26592983c2121fb46f234add1c36b5e596779899d56Mike Isely /* 26692983c2121fb46f234add1c36b5e596779899d56Mike Isely * Mike Isely <isely@pobox.com> 2-Feb-2008: The 26792983c2121fb46f234add1c36b5e596779899d56Mike Isely * Cypress app note that describes this mechanism 26892983c2121fb46f234add1c36b5e596779899d56Mike Isely * states the the low-speed part can't handle more 26992983c2121fb46f234add1c36b5e596779899d56Mike Isely * than 800 bytes/sec, in which case 4800 baud is the 27092983c2121fb46f234add1c36b5e596779899d56Mike Isely * safest speed for a part like that. 27192983c2121fb46f234add1c36b5e596779899d56Mike Isely */ 27292983c2121fb46f234add1c36b5e596779899d56Mike Isely if (new_rate > 4800) { 27392983c2121fb46f234add1c36b5e596779899d56Mike Isely dbg("%s - failed setting baud rate, device incapable " 27492983c2121fb46f234add1c36b5e596779899d56Mike Isely "speed %d", __func__, new_rate); 27592983c2121fb46f234add1c36b5e596779899d56Mike Isely return -1; 27692983c2121fb46f234add1c36b5e596779899d56Mike Isely } 27792983c2121fb46f234add1c36b5e596779899d56Mike Isely } 27892983c2121fb46f234add1c36b5e596779899d56Mike Isely switch (priv->chiptype) { 27992983c2121fb46f234add1c36b5e596779899d56Mike Isely case CT_EARTHMATE: 28092983c2121fb46f234add1c36b5e596779899d56Mike Isely if (new_rate <= 600) { 28192983c2121fb46f234add1c36b5e596779899d56Mike Isely /* 300 and 600 baud rates are supported under 28292983c2121fb46f234add1c36b5e596779899d56Mike Isely * the generic firmware, but are not used with 28392983c2121fb46f234add1c36b5e596779899d56Mike Isely * NMEA and SiRF protocols */ 28492983c2121fb46f234add1c36b5e596779899d56Mike Isely dbg("%s - failed setting baud rate, unsupported speed " 28592983c2121fb46f234add1c36b5e596779899d56Mike Isely "of %d on Earthmate GPS", __func__, new_rate); 28692983c2121fb46f234add1c36b5e596779899d56Mike Isely return -1; 28792983c2121fb46f234add1c36b5e596779899d56Mike Isely } 28892983c2121fb46f234add1c36b5e596779899d56Mike Isely break; 28992983c2121fb46f234add1c36b5e596779899d56Mike Isely default: 29092983c2121fb46f234add1c36b5e596779899d56Mike Isely break; 29192983c2121fb46f234add1c36b5e596779899d56Mike Isely } 29292983c2121fb46f234add1c36b5e596779899d56Mike Isely return new_rate; 29392983c2121fb46f234add1c36b5e596779899d56Mike Isely} 29492983c2121fb46f234add1c36b5e596779899d56Mike Isely 29592983c2121fb46f234add1c36b5e596779899d56Mike Isely 296093cf723b2b06d774929ea07982f6a466ff22314Steven Cole/* This function can either set or retrieve the current serial line settings */ 297813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Coxstatic int cypress_serial_control(struct tty_struct *tty, 29895da310e66ee8090119596c70ca8432e57f9a97fAlan Cox struct usb_serial_port *port, speed_t baud_rate, int data_bits, 29995da310e66ee8090119596c70ca8432e57f9a97fAlan Cox int stop_bits, int parity_enable, int parity_type, int reset, 30095da310e66ee8090119596c70ca8432e57f9a97fAlan Cox int cypress_request_type) 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3023cb4a4f739cccdf0642fa7e3a087e0b8425ff67bLonnie Mendez int new_baudrate = 0, retval = 0, tries = 0; 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct cypress_private *priv; 3040954644bf5a5a2281746516ce0f5df988d504c31Johan Hovold u8 *feature_buffer; 3050954644bf5a5a2281746516ce0f5df988d504c31Johan Hovold const unsigned int feature_len = 5; 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 308441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s", __func__); 309813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv = usb_get_serial_port_data(port); 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31278aef519ed07797f94cff1d0d66dd01704474916Mike Isely if (!priv->comm_is_ok) 31378aef519ed07797f94cff1d0d66dd01704474916Mike Isely return -ENODEV; 31478aef519ed07797f94cff1d0d66dd01704474916Mike Isely 3150954644bf5a5a2281746516ce0f5df988d504c31Johan Hovold feature_buffer = kcalloc(feature_len, sizeof(u8), GFP_KERNEL); 3160954644bf5a5a2281746516ce0f5df988d504c31Johan Hovold if (!feature_buffer) 3170954644bf5a5a2281746516ce0f5df988d504c31Johan Hovold return -ENOMEM; 3180954644bf5a5a2281746516ce0f5df988d504c31Johan Hovold 319813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox switch (cypress_request_type) { 320813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox case CYPRESS_SET_CONFIG: 321813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox /* 0 means 'Hang up' so doesn't change the true bit rate */ 3222805eb13c3b5be7bd6ec7380502bc054b570afd5Mike Frysinger new_baudrate = priv->baud_rate; 3232805eb13c3b5be7bd6ec7380502bc054b570afd5Mike Frysinger if (baud_rate && baud_rate != priv->baud_rate) { 324813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox dbg("%s - baud rate is changing", __func__); 325813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox retval = analyze_baud_rate(port, baud_rate); 3262805eb13c3b5be7bd6ec7380502bc054b570afd5Mike Frysinger if (retval >= 0) { 327813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox new_baudrate = retval; 328813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox dbg("%s - New baud rate set to %d", 329813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox __func__, new_baudrate); 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 331813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox } 332813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox dbg("%s - baud rate is being sent as %d", 333813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox __func__, new_baudrate); 334813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox 335813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox /* fill the feature_buffer with new configuration */ 3360f2c2d7bbb51338fdcda9670795a6c6e348622d9Johan Hovold put_unaligned_le32(new_baudrate, feature_buffer); 337813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox feature_buffer[4] |= data_bits; /* assign data bits in 2 bit space ( max 3 ) */ 338813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox /* 1 bit gap */ 339813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox feature_buffer[4] |= (stop_bits << 3); /* assign stop bits in 1 bit space */ 340813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox feature_buffer[4] |= (parity_enable << 4); /* assign parity flag in 1 bit space */ 341813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox feature_buffer[4] |= (parity_type << 5); /* assign parity type in 1 bit space */ 342813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox /* 1 bit gap */ 343813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox feature_buffer[4] |= (reset << 7); /* assign reset at end of byte, 1 bit space */ 344813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox 345813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox dbg("%s - device is being sent this feature report:", 346813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox __func__); 347813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox dbg("%s - %02X - %02X - %02X - %02X - %02X", __func__, 348813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox feature_buffer[0], feature_buffer[1], 349813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox feature_buffer[2], feature_buffer[3], 350813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox feature_buffer[4]); 351813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox 352813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox do { 353813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox retval = usb_control_msg(port->serial->dev, 354813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox usb_sndctrlpipe(port->serial->dev, 0), 355813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox HID_REQ_SET_REPORT, 356813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox USB_DIR_OUT | USB_RECIP_INTERFACE | USB_TYPE_CLASS, 357813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox 0x0300, 0, feature_buffer, 3580954644bf5a5a2281746516ce0f5df988d504c31Johan Hovold feature_len, 500); 359813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox 360813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox if (tries++ >= 3) 361813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox break; 362813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox 3630954644bf5a5a2281746516ce0f5df988d504c31Johan Hovold } while (retval != feature_len && 364813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox retval != -ENODEV); 365813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox 3660954644bf5a5a2281746516ce0f5df988d504c31Johan Hovold if (retval != feature_len) { 367194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman dev_err(&port->dev, "%s - failed sending serial " 368194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman "line settings - %d\n", __func__, retval); 369813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox cypress_set_dead(port); 370813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox } else { 371813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox spin_lock_irqsave(&priv->lock, flags); 372813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox priv->baud_rate = new_baudrate; 373813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox priv->current_config = feature_buffer[4]; 374813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox spin_unlock_irqrestore(&priv->lock, flags); 375813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox /* If we asked for a speed change encode it */ 376813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox if (baud_rate) 377813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox tty_encode_baud_rate(tty, 378813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox new_baudrate, new_baudrate); 379813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox } 380813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox break; 381813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox case CYPRESS_GET_CONFIG: 382813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox if (priv->get_cfg_unsafe) { 383813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox /* Not implemented for this device, 384813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox and if we try to do it we're likely 385813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox to crash the hardware. */ 3860954644bf5a5a2281746516ce0f5df988d504c31Johan Hovold retval = -ENOTTY; 3870954644bf5a5a2281746516ce0f5df988d504c31Johan Hovold goto out; 388813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox } 389813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox dbg("%s - retreiving serial line settings", __func__); 390813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox do { 391813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox retval = usb_control_msg(port->serial->dev, 392813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox usb_rcvctrlpipe(port->serial->dev, 0), 393813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox HID_REQ_GET_REPORT, 394813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox USB_DIR_IN | USB_RECIP_INTERFACE | USB_TYPE_CLASS, 395813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox 0x0300, 0, feature_buffer, 3960954644bf5a5a2281746516ce0f5df988d504c31Johan Hovold feature_len, 500); 397813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox 398813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox if (tries++ >= 3) 399813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox break; 4000954644bf5a5a2281746516ce0f5df988d504c31Johan Hovold } while (retval != feature_len 401813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox && retval != -ENODEV); 402813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox 4030954644bf5a5a2281746516ce0f5df988d504c31Johan Hovold if (retval != feature_len) { 404194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman dev_err(&port->dev, "%s - failed to retrieve serial " 405194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman "line settings - %d\n", __func__, retval); 406813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox cypress_set_dead(port); 4070954644bf5a5a2281746516ce0f5df988d504c31Johan Hovold goto out; 408813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox } else { 409813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox spin_lock_irqsave(&priv->lock, flags); 410813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox /* store the config in one byte, and later 411813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox use bit masks to check values */ 412813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox priv->current_config = feature_buffer[4]; 4130f2c2d7bbb51338fdcda9670795a6c6e348622d9Johan Hovold priv->baud_rate = get_unaligned_le32(feature_buffer); 414813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox spin_unlock_irqrestore(&priv->lock, flags); 415813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox } 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4173cb4a4f739cccdf0642fa7e3a087e0b8425ff67bLonnie Mendez spin_lock_irqsave(&priv->lock, flags); 4183cb4a4f739cccdf0642fa7e3a087e0b8425ff67bLonnie Mendez ++priv->cmd_count; 4193cb4a4f739cccdf0642fa7e3a087e0b8425ff67bLonnie Mendez spin_unlock_irqrestore(&priv->lock, flags); 4200954644bf5a5a2281746516ce0f5df988d504c31Johan Hovoldout: 4210954644bf5a5a2281746516ce0f5df988d504c31Johan Hovold kfree(feature_buffer); 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* cypress_serial_control */ 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42678aef519ed07797f94cff1d0d66dd01704474916Mike Iselystatic void cypress_set_dead(struct usb_serial_port *port) 42778aef519ed07797f94cff1d0d66dd01704474916Mike Isely{ 42878aef519ed07797f94cff1d0d66dd01704474916Mike Isely struct cypress_private *priv = usb_get_serial_port_data(port); 42978aef519ed07797f94cff1d0d66dd01704474916Mike Isely unsigned long flags; 43078aef519ed07797f94cff1d0d66dd01704474916Mike Isely 43178aef519ed07797f94cff1d0d66dd01704474916Mike Isely spin_lock_irqsave(&priv->lock, flags); 43278aef519ed07797f94cff1d0d66dd01704474916Mike Isely if (!priv->comm_is_ok) { 43378aef519ed07797f94cff1d0d66dd01704474916Mike Isely spin_unlock_irqrestore(&priv->lock, flags); 43478aef519ed07797f94cff1d0d66dd01704474916Mike Isely return; 43578aef519ed07797f94cff1d0d66dd01704474916Mike Isely } 43678aef519ed07797f94cff1d0d66dd01704474916Mike Isely priv->comm_is_ok = 0; 43778aef519ed07797f94cff1d0d66dd01704474916Mike Isely spin_unlock_irqrestore(&priv->lock, flags); 43878aef519ed07797f94cff1d0d66dd01704474916Mike Isely 439194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman dev_err(&port->dev, "cypress_m8 suspending failing port %d - " 440194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman "interval might be too short\n", port->number); 44178aef519ed07797f94cff1d0d66dd01704474916Mike Isely} 44278aef519ed07797f94cff1d0d66dd01704474916Mike Isely 44378aef519ed07797f94cff1d0d66dd01704474916Mike Isely 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/***************************************************************************** 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Cypress serial driver functions 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *****************************************************************************/ 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 449813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Coxstatic int generic_startup(struct usb_serial *serial) 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct cypress_private *priv; 4520257fa9ffe4f0287a9d90476bb733cfc2272396eMike Isely struct usb_serial_port *port = serial->port[0]; 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 454441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - port %d", __func__, port->number); 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 456813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox priv = kzalloc(sizeof(struct cypress_private), GFP_KERNEL); 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!priv) 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 46078aef519ed07797f94cff1d0d66dd01704474916Mike Isely priv->comm_is_ok = !0; 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_init(&priv->lock); 462117fb8d086cfc6e51c729fe5533bb83cb55c150aJohan Hovold if (kfifo_alloc(&priv->write_fifo, CYPRESS_BUF_SIZE, GFP_KERNEL)) { 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(priv); 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_waitqueue_head(&priv->delta_msr_wait); 467813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox 468813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox usb_reset_configuration(serial->dev); 469813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->cmd_ctrl = 0; 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->line_control = 0; 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->termios_initialized = 0; 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->rx_flags = 0; 4743416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely /* Default packet format setting is determined by packet size. 4753416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely Anything with a size larger then 9 must have a separate 4763416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely count field since the 3 bit count field is otherwise too 4773416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely small. Otherwise we can use the slightly more compact 4783416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely format. This is in accordance with the cypress_m8 serial 4793416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely converter app note. */ 480813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox if (port->interrupt_out_size > 9) 4813416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely priv->pkt_fmt = packet_format_1; 482813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox else 4833416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely priv->pkt_fmt = packet_format_2; 484813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox 4850257fa9ffe4f0287a9d90476bb733cfc2272396eMike Isely if (interval > 0) { 4860257fa9ffe4f0287a9d90476bb733cfc2272396eMike Isely priv->write_urb_interval = interval; 4870257fa9ffe4f0287a9d90476bb733cfc2272396eMike Isely priv->read_urb_interval = interval; 4880257fa9ffe4f0287a9d90476bb733cfc2272396eMike Isely dbg("%s - port %d read & write intervals forced to %d", 489813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox __func__, port->number, interval); 4900257fa9ffe4f0287a9d90476bb733cfc2272396eMike Isely } else { 4910257fa9ffe4f0287a9d90476bb733cfc2272396eMike Isely priv->write_urb_interval = port->interrupt_out_urb->interval; 4920257fa9ffe4f0287a9d90476bb733cfc2272396eMike Isely priv->read_urb_interval = port->interrupt_in_urb->interval; 4930257fa9ffe4f0287a9d90476bb733cfc2272396eMike Isely dbg("%s - port %d intervals: read=%d write=%d", 494813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox __func__, port->number, 495813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox priv->read_urb_interval, priv->write_urb_interval); 4960257fa9ffe4f0287a9d90476bb733cfc2272396eMike Isely } 4970257fa9ffe4f0287a9d90476bb733cfc2272396eMike Isely usb_set_serial_port_data(port, priv); 498813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox 499b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez return 0; 500b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez} 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 503813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Coxstatic int cypress_earthmate_startup(struct usb_serial *serial) 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct cypress_private *priv; 5063d6aa3206540e1e68bda9e8ea11ec71444f1ac71Mike Isely struct usb_serial_port *port = serial->port[0]; 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 508441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s", __func__); 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (generic_startup(serial)) { 511441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - Failed setting up port %d", __func__, 5123d6aa3206540e1e68bda9e8ea11ec71444f1ac71Mike Isely port->number); 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5163d6aa3206540e1e68bda9e8ea11ec71444f1ac71Mike Isely priv = usb_get_serial_port_data(port); 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->chiptype = CT_EARTHMATE; 5183416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely /* All Earthmate devices use the separated-count packet 5193416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely format! Idiotic. */ 5203416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely priv->pkt_fmt = packet_format_1; 521813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox if (serial->dev->descriptor.idProduct != 522813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox cpu_to_le16(PRODUCT_ID_EARTHMATEUSB)) { 5233d6aa3206540e1e68bda9e8ea11ec71444f1ac71Mike Isely /* The old original USB Earthmate seemed able to 5243d6aa3206540e1e68bda9e8ea11ec71444f1ac71Mike Isely handle GET_CONFIG requests; everything they've 5253d6aa3206540e1e68bda9e8ea11ec71444f1ac71Mike Isely produced since that time crashes if this command is 5263d6aa3206540e1e68bda9e8ea11ec71444f1ac71Mike Isely attempted :-( */ 5273d6aa3206540e1e68bda9e8ea11ec71444f1ac71Mike Isely dbg("%s - Marking this device as unsafe for GET_CONFIG " 5283d6aa3206540e1e68bda9e8ea11ec71444f1ac71Mike Isely "commands", __func__); 5293d6aa3206540e1e68bda9e8ea11ec71444f1ac71Mike Isely priv->get_cfg_unsafe = !0; 5303d6aa3206540e1e68bda9e8ea11ec71444f1ac71Mike Isely } 531b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez 532b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez return 0; 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* cypress_earthmate_startup */ 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 536813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Coxstatic int cypress_hidcom_startup(struct usb_serial *serial) 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct cypress_private *priv; 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 540441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s", __func__); 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (generic_startup(serial)) { 543441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - Failed setting up port %d", __func__, 544b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez serial->port[0]->number); 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv = usb_get_serial_port_data(serial->port[0]); 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->chiptype = CT_CYPHIDCOM; 550813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox 551b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez return 0; 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* cypress_hidcom_startup */ 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 555813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Coxstatic int cypress_ca42v2_startup(struct usb_serial *serial) 556a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez{ 557a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez struct cypress_private *priv; 558a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez 559441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s", __func__); 560a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez 561a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez if (generic_startup(serial)) { 562441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - Failed setting up port %d", __func__, 563a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez serial->port[0]->number); 564a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez return 1; 565a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez } 566a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez 567a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez priv = usb_get_serial_port_data(serial->port[0]); 568a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez priv->chiptype = CT_CA42V2; 569a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez 570a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez return 0; 571a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez} /* cypress_ca42v2_startup */ 572a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez 573a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez 574f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Sternstatic void cypress_release(struct usb_serial *serial) 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct cypress_private *priv; 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 578813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox dbg("%s - port %d", __func__, serial->port[0]->number); 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* all open ports are closed at this point */ 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv = usb_get_serial_port_data(serial->port[0]); 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (priv) { 585117fb8d086cfc6e51c729fe5533bb83cb55c150aJohan Hovold kfifo_free(&priv->write_fifo); 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(priv); 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 591a509a7e478e4766114d69f12d19d644ac63e9765Alan Coxstatic int cypress_open(struct tty_struct *tty, struct usb_serial_port *port) 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct cypress_private *priv = usb_get_serial_port_data(port); 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_serial *serial = port->serial; 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result = 0; 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 598441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - port %d", __func__, port->number); 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 60078aef519ed07797f94cff1d0d66dd01704474916Mike Isely if (!priv->comm_is_ok) 60178aef519ed07797f94cff1d0d66dd01704474916Mike Isely return -EIO; 60278aef519ed07797f94cff1d0d66dd01704474916Mike Isely 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* clear halts before open */ 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_clear_halt(serial->dev, 0x81); 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_clear_halt(serial->dev, 0x02); 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&priv->lock, flags); 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* reset read/write statistics */ 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->bytes_in = 0; 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->bytes_out = 0; 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->cmd_count = 0; 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->rx_flags = 0; 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 615335f8514f200e63d689113d29cb7253a5c282967Alan Cox /* Set termios */ 616fe1ae7fdd2ee603f2d95f04e09a68f7f79045127Alan Cox cypress_send(port); 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 61895da310e66ee8090119596c70ca8432e57f9a97fAlan Cox if (tty) 61995da310e66ee8090119596c70ca8432e57f9a97fAlan Cox cypress_set_termios(tty, port, &priv->tmp_termios); 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* setup the port and start reading from the device */ 622813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox if (!port->interrupt_in_urb) { 623194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman dev_err(&port->dev, "%s - interrupt_in_urb is empty!\n", 624194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman __func__); 625813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox return -1; 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_fill_int_urb(port->interrupt_in_urb, serial->dev, 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_rcvintpipe(serial->dev, port->interrupt_in_endpointAddress), 630813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox port->interrupt_in_urb->transfer_buffer, 631813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox port->interrupt_in_urb->transfer_buffer_length, 6320257fa9ffe4f0287a9d90476bb733cfc2272396eMike Isely cypress_read_int_callback, port, priv->read_urb_interval); 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 635813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox if (result) { 636813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox dev_err(&port->dev, 637813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox "%s - failed submitting read urb, error %d\n", 638813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox __func__, result); 63978aef519ed07797f94cff1d0d66dd01704474916Mike Isely cypress_set_dead(port); 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 641335f8514f200e63d689113d29cb7253a5c282967Alan Cox port->port.drain_delay = 256; 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return result; 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* cypress_open */ 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 645335f8514f200e63d689113d29cb7253a5c282967Alan Coxstatic void cypress_dtr_rts(struct usb_serial_port *port, int on) 646335f8514f200e63d689113d29cb7253a5c282967Alan Cox{ 647335f8514f200e63d689113d29cb7253a5c282967Alan Cox struct cypress_private *priv = usb_get_serial_port_data(port); 648335f8514f200e63d689113d29cb7253a5c282967Alan Cox /* drop dtr and rts */ 649335f8514f200e63d689113d29cb7253a5c282967Alan Cox spin_lock_irq(&priv->lock); 650335f8514f200e63d689113d29cb7253a5c282967Alan Cox if (on == 0) 651335f8514f200e63d689113d29cb7253a5c282967Alan Cox priv->line_control = 0; 652335f8514f200e63d689113d29cb7253a5c282967Alan Cox else 653335f8514f200e63d689113d29cb7253a5c282967Alan Cox priv->line_control = CONTROL_DTR | CONTROL_RTS; 654335f8514f200e63d689113d29cb7253a5c282967Alan Cox priv->cmd_ctrl = 1; 655335f8514f200e63d689113d29cb7253a5c282967Alan Cox spin_unlock_irq(&priv->lock); 656335f8514f200e63d689113d29cb7253a5c282967Alan Cox cypress_write(NULL, port, NULL, 0); 657335f8514f200e63d689113d29cb7253a5c282967Alan Cox} 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 659335f8514f200e63d689113d29cb7253a5c282967Alan Coxstatic void cypress_close(struct usb_serial_port *port) 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct cypress_private *priv = usb_get_serial_port_data(port); 662117fb8d086cfc6e51c729fe5533bb83cb55c150aJohan Hovold unsigned long flags; 6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 664441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - port %d", __func__, port->number); 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6669e3b1d8e3d5d135ac7be43f6710b7a67b569c292Oliver Neukum /* writing is potentially harmful, lock must be taken */ 6679e3b1d8e3d5d135ac7be43f6710b7a67b569c292Oliver Neukum mutex_lock(&port->serial->disc_mutex); 6689e3b1d8e3d5d135ac7be43f6710b7a67b569c292Oliver Neukum if (port->serial->disconnected) { 6699e3b1d8e3d5d135ac7be43f6710b7a67b569c292Oliver Neukum mutex_unlock(&port->serial->disc_mutex); 6709e3b1d8e3d5d135ac7be43f6710b7a67b569c292Oliver Neukum return; 6719e3b1d8e3d5d135ac7be43f6710b7a67b569c292Oliver Neukum } 672117fb8d086cfc6e51c729fe5533bb83cb55c150aJohan Hovold spin_lock_irqsave(&priv->lock, flags); 673117fb8d086cfc6e51c729fe5533bb83cb55c150aJohan Hovold kfifo_reset_out(&priv->write_fifo); 674117fb8d086cfc6e51c729fe5533bb83cb55c150aJohan Hovold spin_unlock_irqrestore(&priv->lock, flags); 675117fb8d086cfc6e51c729fe5533bb83cb55c150aJohan Hovold 676441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - stopping urbs", __func__); 677813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox usb_kill_urb(port->interrupt_in_urb); 678813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox usb_kill_urb(port->interrupt_out_urb); 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (stats) 681813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox dev_info(&port->dev, "Statistics: %d Bytes In | %d Bytes Out | %d Commands Issued\n", 682813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox priv->bytes_in, priv->bytes_out, priv->cmd_count); 6839e3b1d8e3d5d135ac7be43f6710b7a67b569c292Oliver Neukum mutex_unlock(&port->serial->disc_mutex); 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* cypress_close */ 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 68795da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic int cypress_write(struct tty_struct *tty, struct usb_serial_port *port, 68895da310e66ee8090119596c70ca8432e57f9a97fAlan Cox const unsigned char *buf, int count) 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct cypress_private *priv = usb_get_serial_port_data(port); 691813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox 692441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - port %d, %d bytes", __func__, port->number, count); 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* line control commands, which need to be executed immediately, 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds are not put into the buffer for obvious reasons. 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (priv->cmd_ctrl) { 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count = 0; 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto finish; 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 701813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!count) 7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return count; 704813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox 705117fb8d086cfc6e51c729fe5533bb83cb55c150aJohan Hovold count = kfifo_in_locked(&priv->write_fifo, buf, count, &priv->lock); 7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfinish: 7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cypress_send(port); 7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return count; 7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* cypress_write */ 7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void cypress_send(struct usb_serial_port *port) 7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int count = 0, result, offset, actual_size; 7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct cypress_private *priv = usb_get_serial_port_data(port); 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 719813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox 72078aef519ed07797f94cff1d0d66dd01704474916Mike Isely if (!priv->comm_is_ok) 72178aef519ed07797f94cff1d0d66dd01704474916Mike Isely return; 72278aef519ed07797f94cff1d0d66dd01704474916Mike Isely 723441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - port %d", __func__, port->number); 724813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox dbg("%s - interrupt out size is %d", __func__, 725813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox port->interrupt_out_size); 726813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox 7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&priv->lock, flags); 7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (priv->write_urb_in_use) { 729441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - can't write, urb in use", __func__); 7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* clear buffer */ 736813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox memset(port->interrupt_out_urb->transfer_buffer, 0, 737813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox port->interrupt_out_size); 7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&priv->lock, flags); 7403416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely switch (priv->pkt_fmt) { 7413416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely default: 7423416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely case packet_format_1: 7433416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely /* this is for the CY7C64013... */ 7443416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely offset = 2; 7453416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely port->interrupt_out_buffer[0] = priv->line_control; 7463416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely break; 7473416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely case packet_format_2: 7483416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely /* this is for the CY7C63743... */ 7493416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely offset = 1; 7503416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely port->interrupt_out_buffer[0] = priv->line_control; 7513416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely break; 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (priv->line_control & CONTROL_RESET) 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->line_control &= ~CONTROL_RESET; 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (priv->cmd_ctrl) { 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->cmd_count++; 759441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - line control command being issued", __func__); 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto send; 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 765117fb8d086cfc6e51c729fe5533bb83cb55c150aJohan Hovold count = kfifo_out_locked(&priv->write_fifo, 766117fb8d086cfc6e51c729fe5533bb83cb55c150aJohan Hovold &port->interrupt_out_buffer[offset], 767117fb8d086cfc6e51c729fe5533bb83cb55c150aJohan Hovold port->interrupt_out_size - offset, 768117fb8d086cfc6e51c729fe5533bb83cb55c150aJohan Hovold &priv->lock); 769813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox if (count == 0) 7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7723416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely switch (priv->pkt_fmt) { 7733416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely default: 7743416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely case packet_format_1: 7753416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely port->interrupt_out_buffer[1] = count; 7763416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely break; 7773416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely case packet_format_2: 7783416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely port->interrupt_out_buffer[0] |= count; 7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 781441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - count is %d", __func__, count); 7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssend: 7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&priv->lock, flags); 7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->write_urb_in_use = 1; 7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (priv->cmd_ctrl) 7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds actual_size = 1; 7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 7913416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely actual_size = count + 7923416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely (priv->pkt_fmt == packet_format_1 ? 2 : 1); 7933416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely 794813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox usb_serial_debug_data(debug, &port->dev, __func__, 795813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox port->interrupt_out_size, 796813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox port->interrupt_out_urb->transfer_buffer); 7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7989aa8dae7b1fa7af099a403fc3766e068a0ea6d68Mike Isely usb_fill_int_urb(port->interrupt_out_urb, port->serial->dev, 7999aa8dae7b1fa7af099a403fc3766e068a0ea6d68Mike Isely usb_sndintpipe(port->serial->dev, port->interrupt_out_endpointAddress), 8009aa8dae7b1fa7af099a403fc3766e068a0ea6d68Mike Isely port->interrupt_out_buffer, port->interrupt_out_size, 8019aa8dae7b1fa7af099a403fc3766e068a0ea6d68Mike Isely cypress_write_int_callback, port, priv->write_urb_interval); 802813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox result = usb_submit_urb(port->interrupt_out_urb, GFP_ATOMIC); 8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) { 80422a416c4e0f2179b57028e084ac0ed2c110333bdJohan Hovold dev_err_console(port, 805813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox "%s - failed submitting write urb, error %d\n", 806813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox __func__, result); 8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->write_urb_in_use = 0; 80878aef519ed07797f94cff1d0d66dd01704474916Mike Isely cypress_set_dead(port); 8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&priv->lock, flags); 812813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox if (priv->cmd_ctrl) 8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->cmd_ctrl = 0; 814813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox 815813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox /* do not count the line control and size bytes */ 816813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox priv->bytes_out += count; 8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 819cf2c7481d2ff7f0c266de873b2fe93883e9782f9Pete Zaitcev usb_serial_port_softint(port); 8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* cypress_send */ 8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* returns how much space is available in the soft buffer */ 82495da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic int cypress_write_room(struct tty_struct *tty) 8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 82695da310e66ee8090119596c70ca8432e57f9a97fAlan Cox struct usb_serial_port *port = tty->driver_data; 8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct cypress_private *priv = usb_get_serial_port_data(port); 8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int room = 0; 8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 831441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - port %d", __func__, port->number); 8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&priv->lock, flags); 834117fb8d086cfc6e51c729fe5533bb83cb55c150aJohan Hovold room = kfifo_avail(&priv->write_fifo); 8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 837441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - returns %d", __func__, room); 8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return room; 8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 84260b33c133ca0b7c0b6072c87234b63fee6e80558Alan Coxstatic int cypress_tiocmget(struct tty_struct *tty) 8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 84495da310e66ee8090119596c70ca8432e57f9a97fAlan Cox struct usb_serial_port *port = tty->driver_data; 8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct cypress_private *priv = usb_get_serial_port_data(port); 8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __u8 status, control; 8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int result = 0; 8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 849813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox 850441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - port %d", __func__, port->number); 8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&priv->lock, flags); 8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds control = priv->line_control; 8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = priv->current_status; 8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = ((control & CONTROL_DTR) ? TIOCM_DTR : 0) 8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | ((control & CONTROL_RTS) ? TIOCM_RTS : 0) 8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | ((status & UART_CTS) ? TIOCM_CTS : 0) 8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | ((status & UART_DSR) ? TIOCM_DSR : 0) 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | ((status & UART_RI) ? TIOCM_RI : 0) 8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | ((status & UART_CD) ? TIOCM_CD : 0); 8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 864441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - result = %x", __func__, result); 8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return result; 8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 87020b9d17715017ae4dd4ec87fabc36d33b9de708eAlan Coxstatic int cypress_tiocmset(struct tty_struct *tty, 8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int set, unsigned int clear) 8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 87395da310e66ee8090119596c70ca8432e57f9a97fAlan Cox struct usb_serial_port *port = tty->driver_data; 8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct cypress_private *priv = usb_get_serial_port_data(port); 8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 876813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox 877441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - port %d", __func__, port->number); 8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&priv->lock, flags); 8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (set & TIOCM_RTS) 8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->line_control |= CONTROL_RTS; 8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (set & TIOCM_DTR) 8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->line_control |= CONTROL_DTR; 8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (clear & TIOCM_RTS) 8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->line_control &= ~CONTROL_RTS; 8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (clear & TIOCM_DTR) 8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->line_control &= ~CONTROL_DTR; 8888873aaa6e574d85c020a1c472d6d159cd1ec8aefAlan Cox priv->cmd_ctrl = 1; 8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 89195da310e66ee8090119596c70ca8432e57f9a97fAlan Cox return cypress_write(tty, port, NULL, 0); 8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 89500a0d0d65b61241a718d0aee96f46b9a2d93bf26Alan Coxstatic int cypress_ioctl(struct tty_struct *tty, 89695da310e66ee8090119596c70ca8432e57f9a97fAlan Cox unsigned int cmd, unsigned long arg) 8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 89895da310e66ee8090119596c70ca8432e57f9a97fAlan Cox struct usb_serial_port *port = tty->driver_data; 8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct cypress_private *priv = usb_get_serial_port_data(port); 9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 901441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - port %d, cmd 0x%.4x", __func__, port->number, cmd); 9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cmd) { 904813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox /* This code comes from drivers/char/serial.c and ftdi_sio.c */ 905813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox case TIOCMIWAIT: 906813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox while (priv != NULL) { 907813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox interruptible_sleep_on(&priv->delta_msr_wait); 908813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox /* see if a signal did it */ 909813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox if (signal_pending(current)) 910813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox return -ERESTARTSYS; 911813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox else { 912813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox char diff = priv->diff_status; 913813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox if (diff == 0) 914813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox return -EIO; /* no change => error */ 915813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox 916813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox /* consume all events */ 917813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox priv->diff_status = 0; 918813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox 919813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox /* return 0 if caller wanted to know about 920813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox these bits */ 921813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox if (((arg & TIOCM_RNG) && (diff & UART_RI)) || 922813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox ((arg & TIOCM_DSR) && (diff & UART_DSR)) || 923813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox ((arg & TIOCM_CD) && (diff & UART_CD)) || 924813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox ((arg & TIOCM_CTS) && (diff & UART_CTS))) 925813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox return 0; 926813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox /* otherwise caller can't care less about what 927813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox * happened, and so we continue to wait for 928813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox * more events. 929813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox */ 9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 931813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox } 932813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox return 0; 933813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox default: 934813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox break; 9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 936441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - arg not supported - it was 0x%04x - check include/asm/ioctls.h", __func__, cmd); 9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOIOCTLCMD; 9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* cypress_ioctl */ 9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 94195da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic void cypress_set_termios(struct tty_struct *tty, 94295da310e66ee8090119596c70ca8432e57f9a97fAlan Cox struct usb_serial_port *port, struct ktermios *old_termios) 9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct cypress_private *priv = usb_get_serial_port_data(port); 9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int data_bits, stop_bits, parity_type, parity_enable; 9468873aaa6e574d85c020a1c472d6d159cd1ec8aefAlan Cox unsigned cflag, iflag; 9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __u8 oldlines; 9493cb4a4f739cccdf0642fa7e3a087e0b8425ff67bLonnie Mendez int linechange = 0; 950b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez 951441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - port %d", __func__, port->number); 9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&priv->lock, flags); 954fe1ae7fdd2ee603f2d95f04e09a68f7f79045127Alan Cox /* We can't clean this one up as we don't know the device type 955fe1ae7fdd2ee603f2d95f04e09a68f7f79045127Alan Cox early enough */ 9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!priv->termios_initialized) { 9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (priv->chiptype == CT_EARTHMATE) { 9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *(tty->termios) = tty_std_termios; 959b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez tty->termios->c_cflag = B4800 | CS8 | CREAD | HUPCL | 960b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez CLOCAL; 9618873aaa6e574d85c020a1c472d6d159cd1ec8aefAlan Cox tty->termios->c_ispeed = 4800; 9628873aaa6e574d85c020a1c472d6d159cd1ec8aefAlan Cox tty->termios->c_ospeed = 4800; 9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (priv->chiptype == CT_CYPHIDCOM) { 9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *(tty->termios) = tty_std_termios; 965b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | 966b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez CLOCAL; 9678873aaa6e574d85c020a1c472d6d159cd1ec8aefAlan Cox tty->termios->c_ispeed = 9600; 9688873aaa6e574d85c020a1c472d6d159cd1ec8aefAlan Cox tty->termios->c_ospeed = 9600; 969a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez } else if (priv->chiptype == CT_CA42V2) { 970a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez *(tty->termios) = tty_std_termios; 971a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | 972a5c44e29e5637b5e6fe59d225eb4f438688b3849Lonnie Mendez CLOCAL; 9738873aaa6e574d85c020a1c472d6d159cd1ec8aefAlan Cox tty->termios->c_ispeed = 9600; 9748873aaa6e574d85c020a1c472d6d159cd1ec8aefAlan Cox tty->termios->c_ospeed = 9600; 9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->termios_initialized = 1; 9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9808873aaa6e574d85c020a1c472d6d159cd1ec8aefAlan Cox /* Unsupported features need clearing */ 9818873aaa6e574d85c020a1c472d6d159cd1ec8aefAlan Cox tty->termios->c_cflag &= ~(CMSPAR|CRTSCTS); 9828873aaa6e574d85c020a1c472d6d159cd1ec8aefAlan Cox 9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cflag = tty->termios->c_cflag; 9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iflag = tty->termios->c_iflag; 9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* check if there are new settings */ 9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (old_termios) { 9888873aaa6e574d85c020a1c472d6d159cd1ec8aefAlan Cox spin_lock_irqsave(&priv->lock, flags); 9898873aaa6e574d85c020a1c472d6d159cd1ec8aefAlan Cox priv->tmp_termios = *(tty->termios); 9908873aaa6e574d85c020a1c472d6d159cd1ec8aefAlan Cox spin_unlock_irqrestore(&priv->lock, flags); 9918873aaa6e574d85c020a1c472d6d159cd1ec8aefAlan Cox } 9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* set number of data bits, parity, stop bits */ 9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* when parity is disabled the parity type bit is ignored */ 9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 996b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez /* 1 means 2 stop bits, 0 means 1 stop bit */ 997b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez stop_bits = cflag & CSTOPB ? 1 : 0; 998b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez 9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cflag & PARENB) { 10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds parity_enable = 1; 1001b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez /* 1 means odd parity, 0 means even parity */ 1002b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez parity_type = cflag & PARODD ? 1 : 0; 10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds parity_enable = parity_type = 0; 10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 100677336828c01933d37102c4bef6e2a2cf7e3243b3Alan Cox switch (cflag & CSIZE) { 100777336828c01933d37102c4bef6e2a2cf7e3243b3Alan Cox case CS5: 100877336828c01933d37102c4bef6e2a2cf7e3243b3Alan Cox data_bits = 0; 100977336828c01933d37102c4bef6e2a2cf7e3243b3Alan Cox break; 101077336828c01933d37102c4bef6e2a2cf7e3243b3Alan Cox case CS6: 101177336828c01933d37102c4bef6e2a2cf7e3243b3Alan Cox data_bits = 1; 101277336828c01933d37102c4bef6e2a2cf7e3243b3Alan Cox break; 101377336828c01933d37102c4bef6e2a2cf7e3243b3Alan Cox case CS7: 101477336828c01933d37102c4bef6e2a2cf7e3243b3Alan Cox data_bits = 2; 101577336828c01933d37102c4bef6e2a2cf7e3243b3Alan Cox break; 101677336828c01933d37102c4bef6e2a2cf7e3243b3Alan Cox case CS8: 10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data_bits = 3; 101877336828c01933d37102c4bef6e2a2cf7e3243b3Alan Cox break; 101977336828c01933d37102c4bef6e2a2cf7e3243b3Alan Cox default: 1020194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman dev_err(&port->dev, "%s - CSIZE was set, but not CS5-CS8\n", 1021194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman __func__); 102277336828c01933d37102c4bef6e2a2cf7e3243b3Alan Cox data_bits = 3; 102377336828c01933d37102c4bef6e2a2cf7e3243b3Alan Cox } 10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&priv->lock, flags); 10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds oldlines = priv->line_control; 10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((cflag & CBAUD) == B0) { 10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* drop dtr and rts */ 1028441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - dropping the lines, baud rate 0bps", __func__); 10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS); 10308873aaa6e574d85c020a1c472d6d159cd1ec8aefAlan Cox } else 10313cb4a4f739cccdf0642fa7e3a087e0b8425ff67bLonnie Mendez priv->line_control = (CONTROL_DTR | CONTROL_RTS); 10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1034b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez dbg("%s - sending %d stop_bits, %d parity_enable, %d parity_type, " 1035441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison "%d data_bits (+5)", __func__, stop_bits, 1036b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez parity_enable, parity_type, data_bits); 1037b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez 1038813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox cypress_serial_control(tty, port, tty_get_baud_rate(tty), 1039813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox data_bits, stop_bits, 1040813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox parity_enable, parity_type, 1041813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox 0, CYPRESS_SET_CONFIG); 10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1043b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez /* we perform a CYPRESS_GET_CONFIG so that the current settings are 1044b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez * filled into the private structure this should confirm that all is 1045b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez * working if it returns what we just set */ 104695da310e66ee8090119596c70ca8432e57f9a97fAlan Cox cypress_serial_control(tty, port, 0, 0, 0, 0, 0, 0, CYPRESS_GET_CONFIG); 10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1048b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez /* Here we can define custom tty settings for devices; the main tty 1049b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez * termios flag base comes from empeg.c */ 10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1051b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez spin_lock_irqsave(&priv->lock, flags); 1052813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox if (priv->chiptype == CT_EARTHMATE && priv->baud_rate == 4800) { 1053b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez dbg("Using custom termios settings for a baud rate of " 1054b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez "4800bps."); 10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* define custom termios settings for NMEA protocol */ 10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty->termios->c_iflag /* input modes - */ 1058b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez &= ~(IGNBRK /* disable ignore break */ 1059b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez | BRKINT /* disable break causes interrupt */ 1060b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez | PARMRK /* disable mark parity errors */ 1061b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez | ISTRIP /* disable clear high bit of input char */ 1062b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez | INLCR /* disable translate NL to CR */ 1063b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez | IGNCR /* disable ignore CR */ 1064b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez | ICRNL /* disable translate CR to NL */ 1065b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez | IXON); /* disable enable XON/XOFF flow control */ 1066b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez 10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty->termios->c_oflag /* output modes */ 1068b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez &= ~OPOST; /* disable postprocess output char */ 10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1070b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez tty->termios->c_lflag /* line discipline modes */ 1071b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez &= ~(ECHO /* disable echo input characters */ 1072b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez | ECHONL /* disable echo new line */ 1073b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez | ICANON /* disable erase, kill, werase, and rprnt 1074b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez special characters */ 1075b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez | ISIG /* disable interrupt, quit, and suspend 1076b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez special characters */ 1077b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez | IEXTEN); /* disable non-POSIX special characters */ 10783cb4a4f739cccdf0642fa7e3a087e0b8425ff67bLonnie Mendez } /* CT_CYPHIDCOM: Application should handle this for device */ 10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds linechange = (priv->line_control != oldlines); 10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* if necessary, set lines */ 10843cb4a4f739cccdf0642fa7e3a087e0b8425ff67bLonnie Mendez if (linechange) { 10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->cmd_ctrl = 1; 108695da310e66ee8090119596c70ca8432e57f9a97fAlan Cox cypress_write(tty, port, NULL, 0); 10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* cypress_set_termios */ 10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1090b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez 10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* returns amount of data still left in soft buffer */ 109295da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic int cypress_chars_in_buffer(struct tty_struct *tty) 10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 109495da310e66ee8090119596c70ca8432e57f9a97fAlan Cox struct usb_serial_port *port = tty->driver_data; 10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct cypress_private *priv = usb_get_serial_port_data(port); 10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int chars = 0; 10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1099441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - port %d", __func__, port->number); 1100813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox 11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&priv->lock, flags); 1102117fb8d086cfc6e51c729fe5533bb83cb55c150aJohan Hovold chars = kfifo_len(&priv->write_fifo); 11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1105441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - returns %d", __func__, chars); 11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return chars; 11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 111095da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic void cypress_throttle(struct tty_struct *tty) 11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 111295da310e66ee8090119596c70ca8432e57f9a97fAlan Cox struct usb_serial_port *port = tty->driver_data; 11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct cypress_private *priv = usb_get_serial_port_data(port); 11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1115441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - port %d", __func__, port->number); 11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1117638325154572ba2113a18669fe3b299caa2dabd9Oliver Neukum spin_lock_irq(&priv->lock); 11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->rx_flags = THROTTLED; 1119638325154572ba2113a18669fe3b299caa2dabd9Oliver Neukum spin_unlock_irq(&priv->lock); 11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 112395da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic void cypress_unthrottle(struct tty_struct *tty) 11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 112595da310e66ee8090119596c70ca8432e57f9a97fAlan Cox struct usb_serial_port *port = tty->driver_data; 11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct cypress_private *priv = usb_get_serial_port_data(port); 11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int actually_throttled, result; 11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1129441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - port %d", __func__, port->number); 11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1131638325154572ba2113a18669fe3b299caa2dabd9Oliver Neukum spin_lock_irq(&priv->lock); 11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds actually_throttled = priv->rx_flags & ACTUALLY_THROTTLED; 11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->rx_flags = 0; 1134638325154572ba2113a18669fe3b299caa2dabd9Oliver Neukum spin_unlock_irq(&priv->lock); 11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 113678aef519ed07797f94cff1d0d66dd01704474916Mike Isely if (!priv->comm_is_ok) 113778aef519ed07797f94cff1d0d66dd01704474916Mike Isely return; 113878aef519ed07797f94cff1d0d66dd01704474916Mike Isely 11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (actually_throttled) { 1140638325154572ba2113a18669fe3b299caa2dabd9Oliver Neukum result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); 114178aef519ed07797f94cff1d0d66dd01704474916Mike Isely if (result) { 1142b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez dev_err(&port->dev, "%s - failed submitting read urb, " 1143441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison "error %d\n", __func__, result); 114478aef519ed07797f94cff1d0d66dd01704474916Mike Isely cypress_set_dead(port); 114578aef519ed07797f94cff1d0d66dd01704474916Mike Isely } 11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11507d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void cypress_read_int_callback(struct urb *urb) 11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1152cdc97792289179974af6dda781c855696358d307Ming Lei struct usb_serial_port *port = urb->context; 11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct cypress_private *priv = usb_get_serial_port_data(port); 11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct tty_struct *tty; 11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *data = urb->transfer_buffer; 11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 1157b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez char tty_flag = TTY_NORMAL; 11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int havedata = 0; 11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int bytes = 0; 11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result; 11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i = 0; 11628d7bc55ecf86d1488996c4619642b4557e5e42f1Greg Kroah-Hartman int status = urb->status; 11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1164441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - port %d", __func__, port->number); 11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11668d7bc55ecf86d1488996c4619642b4557e5e42f1Greg Kroah-Hartman switch (status) { 116778aef519ed07797f94cff1d0d66dd01704474916Mike Isely case 0: /* success */ 116878aef519ed07797f94cff1d0d66dd01704474916Mike Isely break; 116978aef519ed07797f94cff1d0d66dd01704474916Mike Isely case -ECONNRESET: 117078aef519ed07797f94cff1d0d66dd01704474916Mike Isely case -ENOENT: 117178aef519ed07797f94cff1d0d66dd01704474916Mike Isely case -ESHUTDOWN: 117278aef519ed07797f94cff1d0d66dd01704474916Mike Isely /* precursor to disconnect so just go away */ 117378aef519ed07797f94cff1d0d66dd01704474916Mike Isely return; 117478aef519ed07797f94cff1d0d66dd01704474916Mike Isely case -EPIPE: 11754d2fae8b3597bc787f1f1c06637ce5ab8187e5a7Alan Stern /* Can't call usb_clear_halt while in_interrupt */ 11764d2fae8b3597bc787f1f1c06637ce5ab8187e5a7Alan Stern /* FALLS THROUGH */ 117778aef519ed07797f94cff1d0d66dd01704474916Mike Isely default: 117878aef519ed07797f94cff1d0d66dd01704474916Mike Isely /* something ugly is going on... */ 1179813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox dev_err(&urb->dev->dev, 1180813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox "%s - unexpected nonzero read status received: %d\n", 1181813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox __func__, status); 118278aef519ed07797f94cff1d0d66dd01704474916Mike Isely cypress_set_dead(port); 11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&priv->lock, flags); 11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (priv->rx_flags & THROTTLED) { 1188441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - now throttling", __func__); 11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->rx_flags |= ACTUALLY_THROTTLED; 11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11954a90f09b20f4622dcbff1f0e1e6bae1704f8ad8cAlan Cox tty = tty_port_tty_get(&port->port); 11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!tty) { 1197441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - bad tty pointer - exiting", __func__); 11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&priv->lock, flags); 12023416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely result = urb->actual_length; 12033416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely switch (priv->pkt_fmt) { 12043416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely default: 12053416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely case packet_format_1: 12063416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely /* This is for the CY7C64013... */ 12073416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely priv->current_status = data[0] & 0xF8; 12083416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely bytes = data[1] + 2; 12093416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely i = 2; 12103416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely if (bytes > 2) 12113416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely havedata = 1; 12123416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely break; 12133416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely case packet_format_2: 12143416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely /* This is for the CY7C63743... */ 12153416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely priv->current_status = data[0] & 0xF8; 12163416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely bytes = (data[0] & 0x07) + 1; 12173416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely i = 1; 12183416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely if (bytes > 1) 12193416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely havedata = 1; 12203416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely break; 12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 12233416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely if (result < bytes) { 12243416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely dbg("%s - wrong packet size - received %d bytes but packet " 12253416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely "said %d bytes", __func__, result, bytes); 12263416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely goto continue_read; 12273416eaa1f8f8d516b77de514e14cf8da256d28fbMike Isely } 12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1229813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox usb_serial_debug_data(debug, &port->dev, __func__, 1230813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox urb->actual_length, data); 12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&priv->lock, flags); 12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* check to see if status has changed */ 12346768306c3d9568bc66dc22f8b863bfbda3e7c4d2Mike Isely if (priv->current_status != priv->prev_status) { 12356768306c3d9568bc66dc22f8b863bfbda3e7c4d2Mike Isely priv->diff_status |= priv->current_status ^ 12366768306c3d9568bc66dc22f8b863bfbda3e7c4d2Mike Isely priv->prev_status; 12376768306c3d9568bc66dc22f8b863bfbda3e7c4d2Mike Isely wake_up_interruptible(&priv->delta_msr_wait); 12386768306c3d9568bc66dc22f8b863bfbda3e7c4d2Mike Isely priv->prev_status = priv->current_status; 12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1240b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez spin_unlock_irqrestore(&priv->lock, flags); 12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1242b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez /* hangup, as defined in acm.c... this might be a bad place for it 1243b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez * though */ 1244b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez if (tty && !(tty->termios->c_cflag & CLOCAL) && 1245b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez !(priv->current_status & UART_CD)) { 1246441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - calling hangup", __func__); 12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty_hangup(tty); 12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto continue_read; 12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1251b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez /* There is one error bit... I'm assuming it is a parity error 1252b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez * indicator as the generic firmware will set this bit to 1 if a 1253b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez * parity error occurs. 1254b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez * I can not find reference to any other error events. */ 12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&priv->lock, flags); 12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (priv->current_status & CYP_ERROR) { 12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty_flag = TTY_PARITY; 1259441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - Parity Error detected", __func__); 12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* process read if there is data other than line status */ 1264a108bfcb372d8c4452701039308fb95747911c59Alan Cox if (tty && bytes > i) { 1265a108bfcb372d8c4452701039308fb95747911c59Alan Cox tty_insert_flip_string_fixed_flag(tty, data + i, 126670ced221cc9f041481f129e63cc5b1dedb0ff959Johan Hovold tty_flag, bytes - i); 12674a90f09b20f4622dcbff1f0e1e6bae1704f8ad8cAlan Cox tty_flip_buffer_push(tty); 12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&priv->lock, flags); 1271b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez /* control and status byte(s) are also counted */ 1272b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez priv->bytes_in += bytes; 12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscontinue_read: 12764a90f09b20f4622dcbff1f0e1e6bae1704f8ad8cAlan Cox tty_kref_put(tty); 1277b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez 12781f87158e44e79e62c8250f278c225ce4ab695f4bAlan Stern /* Continue trying to always read */ 12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12801f87158e44e79e62c8250f278c225ce4ab695f4bAlan Stern if (priv->comm_is_ok) { 1281b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez usb_fill_int_urb(port->interrupt_in_urb, port->serial->dev, 1282b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez usb_rcvintpipe(port->serial->dev, 1283b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez port->interrupt_in_endpointAddress), 1284b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez port->interrupt_in_urb->transfer_buffer, 1285b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez port->interrupt_in_urb->transfer_buffer_length, 1286813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox cypress_read_int_callback, port, 1287813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox priv->read_urb_interval); 1288b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); 12891f87158e44e79e62c8250f278c225ce4ab695f4bAlan Stern if (result && result != -EPERM) { 1290b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez dev_err(&urb->dev->dev, "%s - failed resubmitting " 1291441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison "read urb, error %d\n", __func__, 1292b9db07fba7f113764d7379b0f68324a9a5450306Lonnie Mendez result); 129378aef519ed07797f94cff1d0d66dd01704474916Mike Isely cypress_set_dead(port); 129478aef519ed07797f94cff1d0d66dd01704474916Mike Isely } 12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* cypress_read_int_callback */ 12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12997d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void cypress_write_int_callback(struct urb *urb) 13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1301cdc97792289179974af6dda781c855696358d307Ming Lei struct usb_serial_port *port = urb->context; 13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct cypress_private *priv = usb_get_serial_port_data(port); 13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result; 13048d7bc55ecf86d1488996c4619642b4557e5e42f1Greg Kroah-Hartman int status = urb->status; 13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1306441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - port %d", __func__, port->number); 13078d7bc55ecf86d1488996c4619642b4557e5e42f1Greg Kroah-Hartman 13088d7bc55ecf86d1488996c4619642b4557e5e42f1Greg Kroah-Hartman switch (status) { 1309813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox case 0: 1310813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox /* success */ 1311813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox break; 1312813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox case -ECONNRESET: 1313813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox case -ENOENT: 1314813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox case -ESHUTDOWN: 1315813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox /* this urb is terminated, clean up */ 1316813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox dbg("%s - urb shutting down with status: %d", 1317813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox __func__, status); 1318813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox priv->write_urb_in_use = 0; 1319813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox return; 1320813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox case -EPIPE: /* no break needed; clear halt and resubmit */ 1321813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox if (!priv->comm_is_ok) 13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1323813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox usb_clear_halt(port->serial->dev, 0x02); 1324813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox /* error in the urb, so we have to resubmit it */ 1325813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox dbg("%s - nonzero write bulk status received: %d", 1326813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox __func__, status); 1327813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox port->interrupt_out_urb->transfer_buffer_length = 1; 1328813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox result = usb_submit_urb(port->interrupt_out_urb, GFP_ATOMIC); 1329813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox if (!result) 13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 1331813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox dev_err(&urb->dev->dev, 1332813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox "%s - failed resubmitting write urb, error %d\n", 1333813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox __func__, result); 1334813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox cypress_set_dead(port); 1335813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox break; 1336813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox default: 1337813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox dev_err(&urb->dev->dev, 1338813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox "%s - unexpected nonzero write status received: %d\n", 1339813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox __func__, status); 1340813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox cypress_set_dead(port); 1341813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox break; 13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->write_urb_in_use = 0; 1344813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan Cox 13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* send any buffered data */ 13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cypress_send(port); 13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13497e3131f897969f94f605f3e929e2da35202c86d6Greg Kroah-Hartmanmodule_usb_serial_driver(cypress_driver, serial_drivers); 13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1351813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan CoxMODULE_AUTHOR(DRIVER_AUTHOR); 1352813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan CoxMODULE_DESCRIPTION(DRIVER_DESC); 1353813a224fa5bff3e34309a6494e231d5ebfa0fb4eAlan CoxMODULE_VERSION(DRIVER_VERSION); 13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(debug, bool, S_IRUGO | S_IWUSR); 13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(debug, "Debug enabled or not"); 13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(stats, bool, S_IRUGO | S_IWUSR); 13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(stats, "Enable statistics or not"); 13603cb4a4f739cccdf0642fa7e3a087e0b8425ff67bLonnie Mendezmodule_param(interval, int, S_IRUGO | S_IWUSR); 13613cb4a4f739cccdf0642fa7e3a087e0b8425ff67bLonnie MendezMODULE_PARM_DESC(interval, "Overrides interrupt interval"); 1362c312659c5ff1e54bac2d91e1ce1005d58784a7b5Mike Frysingermodule_param(unstable_bauds, bool, S_IRUGO | S_IWUSR); 1363c312659c5ff1e54bac2d91e1ce1005d58784a7b5Mike FrysingerMODULE_PARM_DESC(unstable_bauds, "Allow unstable baud rates"); 1364