diff options
Diffstat (limited to 'drivers/usb/serial/cypress_m8.c')
| -rw-r--r-- | drivers/usb/serial/cypress_m8.c | 543 | 
1 files changed, 184 insertions, 359 deletions
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index 2edf238b00b..01bf5339281 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -16,32 +16,6 @@   *   * See http://geocities.com/i0xox0i for information on this driver and the   * earthmate usb device. - * - *  Lonnie Mendez <dignome@gmail.com> - *  4-29-2005 - *	Fixed problem where setting or retreiving the serial config would fail - *	with EPIPE.  Removed CRTS toggling so the driver behaves more like - *	other usbserial adapters.  Issued new interval of 1ms instead of the - *	default 10ms.  As a result, transfer speed has been substantially - *	increased from avg. 850bps to avg. 3300bps.  initial termios has also - *	been modified.  Cleaned up code and formatting issues so it is more - *	readable.  Replaced the C++ style comments. - * - *  Lonnie Mendez <dignome@gmail.com> - *  12-15-2004 - *	Incorporated write buffering from pl2303 driver.  Fixed bug with line - *	handling so both lines are raised in cypress_open. (was dropping rts) - *      Various code cleanups made as well along with other misc bug fixes. - * - *  Lonnie Mendez <dignome@gmail.com> - *  04-10-2004 - *	Driver modified to support dynamic line settings.  Various improvments - *      and features. - * - *  Neil Whelchel - *  10-2003 - *	Driver first released. - *   */  /* Thanks to Neil Whelchel for writing the first cypress m8 implementation @@ -53,7 +27,6 @@  #include <linux/kernel.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/tty.h>  #include <linux/tty_driver.h> @@ -72,15 +45,10 @@  #include "cypress_m8.h" -static int debug; -static int stats; +static bool stats;  static int interval; -static int unstable_bauds; +static bool unstable_bauds; -/* - * Version Information - */ -#define DRIVER_VERSION "v1.10"  #define DRIVER_AUTHOR "Lonnie Mendez <dignome@gmail.com>, Neil Whelchel <koyama@firstlight.net>"  #define DRIVER_DESC "Cypress USB to Serial Driver" @@ -96,6 +64,7 @@ static const struct usb_device_id id_table_earthmate[] = {  static const struct usb_device_id id_table_cyphidcomrs232[] = {  	{ USB_DEVICE(VENDOR_ID_CYPRESS, PRODUCT_ID_CYPHIDCOM) },  	{ USB_DEVICE(VENDOR_ID_POWERCOM, PRODUCT_ID_UPS) }, +	{ USB_DEVICE(VENDOR_ID_FRWD, PRODUCT_ID_CYPHIDCOM_FRWD) },  	{ }						/* Terminating entry */  }; @@ -109,20 +78,13 @@ static const struct usb_device_id id_table_combined[] = {  	{ USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB_LT20) },  	{ USB_DEVICE(VENDOR_ID_CYPRESS, PRODUCT_ID_CYPHIDCOM) },  	{ USB_DEVICE(VENDOR_ID_POWERCOM, PRODUCT_ID_UPS) }, +	{ USB_DEVICE(VENDOR_ID_FRWD, PRODUCT_ID_CYPHIDCOM_FRWD) },  	{ USB_DEVICE(VENDOR_ID_DAZZLE, PRODUCT_ID_CA42) },  	{ }						/* Terminating entry */  };  MODULE_DEVICE_TABLE(usb, id_table_combined); -static struct usb_driver cypress_driver = { -	.name =		"cypress", -	.probe =	usb_serial_probe, -	.disconnect =	usb_serial_disconnect, -	.id_table =	id_table_combined, -	.no_dynamic_id = 	1, -}; -  enum packet_format {  	packet_format_1,  /* b0:status, b1:payload count */  	packet_format_2   /* b0[7:3]:status, b0[2:0]:payload count */ @@ -150,18 +112,17 @@ struct cypress_private {  	int baud_rate;			   /* stores current baud rate in  					      integer form */  	int isthrottled;		   /* if throttled, discard reads */ -	wait_queue_head_t delta_msr_wait;  /* used for TIOCMIWAIT */ -	char prev_status, diff_status;	   /* used for TIOCMIWAIT */ +	char prev_status;		   /* used for TIOCMIWAIT */  	/* we pass a pointer to this as the argument sent to  	   cypress_set_termios old_termios */  	struct ktermios tmp_termios; 	   /* stores the old termios settings */  };  /* function prototypes for the Cypress USB to serial device */ -static int  cypress_earthmate_startup(struct usb_serial *serial); -static int  cypress_hidcom_startup(struct usb_serial *serial); -static int  cypress_ca42v2_startup(struct usb_serial *serial); -static void cypress_release(struct usb_serial *serial); +static int  cypress_earthmate_port_probe(struct usb_serial_port *port); +static int  cypress_hidcom_port_probe(struct usb_serial_port *port); +static int  cypress_ca42v2_port_probe(struct usb_serial_port *port); +static int  cypress_port_remove(struct usb_serial_port *port);  static int  cypress_open(struct tty_struct *tty, struct usb_serial_port *port);  static void cypress_close(struct usb_serial_port *port);  static void cypress_dtr_rts(struct usb_serial_port *port, int on); @@ -169,12 +130,10 @@ static int  cypress_write(struct tty_struct *tty, struct usb_serial_port *port,  			const unsigned char *buf, int count);  static void cypress_send(struct usb_serial_port *port);  static int  cypress_write_room(struct tty_struct *tty); -static int  cypress_ioctl(struct tty_struct *tty, struct file *file, -			unsigned int cmd, unsigned long arg);  static void cypress_set_termios(struct tty_struct *tty,  			struct usb_serial_port *port, struct ktermios *old); -static int  cypress_tiocmget(struct tty_struct *tty, struct file *file); -static int  cypress_tiocmset(struct tty_struct *tty, struct file *file, +static int  cypress_tiocmget(struct tty_struct *tty); +static int  cypress_tiocmset(struct tty_struct *tty,  			unsigned int set, unsigned int clear);  static int  cypress_chars_in_buffer(struct tty_struct *tty);  static void cypress_throttle(struct tty_struct *tty); @@ -189,20 +148,19 @@ static struct usb_serial_driver cypress_earthmate_device = {  		.name =			"earthmate",  	},  	.description =			"DeLorme Earthmate USB", -	.usb_driver = 			&cypress_driver,  	.id_table =			id_table_earthmate,  	.num_ports =			1, -	.attach =			cypress_earthmate_startup, -	.release =			cypress_release, +	.port_probe =			cypress_earthmate_port_probe, +	.port_remove =			cypress_port_remove,  	.open =				cypress_open,  	.close =			cypress_close,  	.dtr_rts =			cypress_dtr_rts,  	.write =			cypress_write,  	.write_room =			cypress_write_room, -	.ioctl =			cypress_ioctl,  	.set_termios =			cypress_set_termios,  	.tiocmget =			cypress_tiocmget,  	.tiocmset =			cypress_tiocmset, +	.tiocmiwait =			usb_serial_generic_tiocmiwait,  	.chars_in_buffer =		cypress_chars_in_buffer,  	.throttle =		 	cypress_throttle,  	.unthrottle =			cypress_unthrottle, @@ -216,20 +174,19 @@ static struct usb_serial_driver cypress_hidcom_device = {  		.name =			"cyphidcom",  	},  	.description =			"HID->COM RS232 Adapter", -	.usb_driver = 			&cypress_driver,  	.id_table =			id_table_cyphidcomrs232,  	.num_ports =			1, -	.attach =			cypress_hidcom_startup, -	.release =			cypress_release, +	.port_probe =			cypress_hidcom_port_probe, +	.port_remove =			cypress_port_remove,  	.open =				cypress_open,  	.close =			cypress_close,  	.dtr_rts =			cypress_dtr_rts,  	.write =			cypress_write,  	.write_room =			cypress_write_room, -	.ioctl =			cypress_ioctl,  	.set_termios =			cypress_set_termios,  	.tiocmget =			cypress_tiocmget,  	.tiocmset =			cypress_tiocmset, +	.tiocmiwait =			usb_serial_generic_tiocmiwait,  	.chars_in_buffer =		cypress_chars_in_buffer,  	.throttle =			cypress_throttle,  	.unthrottle =			cypress_unthrottle, @@ -243,20 +200,19 @@ static struct usb_serial_driver cypress_ca42v2_device = {  		.name =			"nokiaca42v2",  	},  	.description =			"Nokia CA-42 V2 Adapter", -	.usb_driver = 			&cypress_driver,  	.id_table =			id_table_nokiaca42v2,  	.num_ports =			1, -	.attach =			cypress_ca42v2_startup, -	.release =			cypress_release, +	.port_probe =			cypress_ca42v2_port_probe, +	.port_remove =			cypress_port_remove,  	.open =				cypress_open,  	.close =			cypress_close,  	.dtr_rts =			cypress_dtr_rts,  	.write =			cypress_write,  	.write_room =			cypress_write_room, -	.ioctl =			cypress_ioctl,  	.set_termios =			cypress_set_termios,  	.tiocmget =			cypress_tiocmget,  	.tiocmset =			cypress_tiocmset, +	.tiocmiwait =			usb_serial_generic_tiocmiwait,  	.chars_in_buffer =		cypress_chars_in_buffer,  	.throttle =			cypress_throttle,  	.unthrottle =			cypress_unthrottle, @@ -264,10 +220,21 @@ static struct usb_serial_driver cypress_ca42v2_device = {  	.write_int_callback =		cypress_write_int_callback,  }; +static struct usb_serial_driver * const serial_drivers[] = { +	&cypress_earthmate_device, &cypress_hidcom_device, +	&cypress_ca42v2_device, NULL +}; +  /*****************************************************************************   * Cypress serial helper functions   *****************************************************************************/ +/* FRWD Dongle hidcom needs to skip reset and speed checks */ +static inline bool is_frwd(struct usb_device *dev) +{ +	return ((le16_to_cpu(dev->descriptor.idVendor) == VENDOR_ID_FRWD) && +		(le16_to_cpu(dev->descriptor.idProduct) == PRODUCT_ID_CYPHIDCOM_FRWD)); +}  static int analyze_baud_rate(struct usb_serial_port *port, speed_t new_rate)  { @@ -277,6 +244,10 @@ static int analyze_baud_rate(struct usb_serial_port *port, speed_t new_rate)  	if (unstable_bauds)  		return new_rate; +	/* FRWD Dongle uses 115200 bps */ +	if (is_frwd(port->serial->dev)) +		return new_rate; +  	/*  	 * The general purpose firmware for the Cypress M8 allows for  	 * a maximum speed of 57600bps (I have no idea whether DeLorme @@ -295,8 +266,9 @@ static int analyze_baud_rate(struct usb_serial_port *port, speed_t new_rate)  		 * safest speed for a part like that.  		 */  		if (new_rate > 4800) { -			dbg("%s - failed setting baud rate, device incapable " -			    "speed %d", __func__, new_rate); +			dev_dbg(&port->dev, +				"%s - failed setting baud rate, device incapable speed %d\n", +				__func__, new_rate);  			return -1;  		}  	} @@ -306,8 +278,9 @@ static int analyze_baud_rate(struct usb_serial_port *port, speed_t new_rate)  			/* 300 and 600 baud rates are supported under  			 * the generic firmware, but are not used with  			 * NMEA and SiRF protocols */ -			dbg("%s - failed setting baud rate, unsupported speed " -			    "of %d on Earthmate GPS", __func__, new_rate); +			dev_dbg(&port->dev, +				"%s - failed setting baud rate, unsupported speed of %d on Earthmate GPS\n", +				__func__, new_rate);  			return -1;  		}  		break; @@ -326,12 +299,11 @@ static int cypress_serial_control(struct tty_struct *tty,  {  	int new_baudrate = 0, retval = 0, tries = 0;  	struct cypress_private *priv; +	struct device *dev = &port->dev;  	u8 *feature_buffer;  	const unsigned int feature_len = 5;  	unsigned long flags; -	dbg("%s", __func__); -  	priv = usb_get_serial_port_data(port);  	if (!priv->comm_is_ok) @@ -346,16 +318,16 @@ static int cypress_serial_control(struct tty_struct *tty,  		/* 0 means 'Hang up' so doesn't change the true bit rate */  		new_baudrate = priv->baud_rate;  		if (baud_rate && baud_rate != priv->baud_rate) { -			dbg("%s - baud rate is changing", __func__); +			dev_dbg(dev, "%s - baud rate is changing\n", __func__);  			retval = analyze_baud_rate(port, baud_rate);  			if (retval >= 0) {  				new_baudrate = retval; -				dbg("%s - New baud rate set to %d", -				    __func__, new_baudrate); +				dev_dbg(dev, "%s - New baud rate set to %d\n", +					__func__, new_baudrate);  			}  		} -		dbg("%s - baud rate is being sent as %d", -					__func__, new_baudrate); +		dev_dbg(dev, "%s - baud rate is being sent as %d\n", __func__, +			new_baudrate);  		/* fill the feature_buffer with new configuration */  		put_unaligned_le32(new_baudrate, feature_buffer); @@ -367,9 +339,8 @@ static int cypress_serial_control(struct tty_struct *tty,  		/* 1 bit gap */  		feature_buffer[4] |= (reset << 7);   /* assign reset at end of byte, 1 bit space */ -		dbg("%s - device is being sent this feature report:", -								__func__); -		dbg("%s - %02X - %02X - %02X - %02X - %02X", __func__, +		dev_dbg(dev, "%s - device is being sent this feature report:\n", __func__); +		dev_dbg(dev, "%s - %02X - %02X - %02X - %02X - %02X\n", __func__,  			feature_buffer[0], feature_buffer[1],  			feature_buffer[2], feature_buffer[3],  			feature_buffer[4]); @@ -389,8 +360,8 @@ static int cypress_serial_control(struct tty_struct *tty,  			 retval != -ENODEV);  		if (retval != feature_len) { -			dev_err(&port->dev, "%s - failed sending serial " -				"line settings - %d\n", __func__, retval); +			dev_err(dev, "%s - failed sending serial line settings - %d\n", +				__func__, retval);  			cypress_set_dead(port);  		} else {  			spin_lock_irqsave(&priv->lock, flags); @@ -411,7 +382,7 @@ static int cypress_serial_control(struct tty_struct *tty,  			retval = -ENOTTY;  			goto out;  		} -		dbg("%s - retreiving serial line settings", __func__); +		dev_dbg(dev, "%s - retreiving serial line settings\n", __func__);  		do {  			retval = usb_control_msg(port->serial->dev,  					usb_rcvctrlpipe(port->serial->dev, 0), @@ -426,8 +397,8 @@ static int cypress_serial_control(struct tty_struct *tty,  						&& retval != -ENODEV);  		if (retval != feature_len) { -			dev_err(&port->dev, "%s - failed to retrieve serial " -				"line settings - %d\n", __func__, retval); +			dev_err(dev, "%s - failed to retrieve serial line settings - %d\n", +				__func__, retval);  			cypress_set_dead(port);  			goto out;  		} else { @@ -462,7 +433,7 @@ static void cypress_set_dead(struct usb_serial_port *port)  	spin_unlock_irqrestore(&priv->lock, flags);  	dev_err(&port->dev, "cypress_m8 suspending failing port %d - " -		"interval might be too short\n", port->number); +		"interval might be too short\n", port->port_number);  } @@ -471,12 +442,10 @@ static void cypress_set_dead(struct usb_serial_port *port)   *****************************************************************************/ -static int generic_startup(struct usb_serial *serial) +static int cypress_generic_port_probe(struct usb_serial_port *port)  { +	struct usb_serial *serial = port->serial;  	struct cypress_private *priv; -	struct usb_serial_port *port = serial->port[0]; - -	dbg("%s - port %d", __func__, port->number);  	priv = kzalloc(sizeof(struct cypress_private), GFP_KERNEL);  	if (!priv) @@ -488,9 +457,12 @@ static int generic_startup(struct usb_serial *serial)  		kfree(priv);  		return -ENOMEM;  	} -	init_waitqueue_head(&priv->delta_msr_wait); -	usb_reset_configuration(serial->dev); +	/* Skip reset for FRWD device. It is a workaound: +	   device hangs if it receives SET_CONFIGURE in Configured +	   state. */ +	if (!is_frwd(serial->dev)) +		usb_reset_configuration(serial->dev);  	priv->cmd_ctrl = 0;  	priv->line_control = 0; @@ -510,32 +482,33 @@ static int generic_startup(struct usb_serial *serial)  	if (interval > 0) {  		priv->write_urb_interval = interval;  		priv->read_urb_interval = interval; -		dbg("%s - port %d read & write intervals forced to %d", -		    __func__, port->number, interval); +		dev_dbg(&port->dev, "%s - read & write intervals forced to %d\n", +			__func__, interval);  	} else {  		priv->write_urb_interval = port->interrupt_out_urb->interval;  		priv->read_urb_interval = port->interrupt_in_urb->interval; -		dbg("%s - port %d intervals: read=%d write=%d", -		    __func__, port->number, -		    priv->read_urb_interval, priv->write_urb_interval); +		dev_dbg(&port->dev, "%s - intervals: read=%d write=%d\n", +			__func__, priv->read_urb_interval, +			priv->write_urb_interval);  	}  	usb_set_serial_port_data(port, priv); +	port->port.drain_delay = 256; +  	return 0;  } -static int cypress_earthmate_startup(struct usb_serial *serial) +static int cypress_earthmate_port_probe(struct usb_serial_port *port)  { +	struct usb_serial *serial = port->serial;  	struct cypress_private *priv; -	struct usb_serial_port *port = serial->port[0]; - -	dbg("%s", __func__); +	int ret; -	if (generic_startup(serial)) { -		dbg("%s - Failed setting up port %d", __func__, -				port->number); -		return 1; +	ret = cypress_generic_port_probe(port); +	if (ret) { +		dev_dbg(&port->dev, "%s - Failed setting up port\n", __func__); +		return ret;  	}  	priv = usb_get_serial_port_data(port); @@ -549,70 +522,61 @@ static int cypress_earthmate_startup(struct usb_serial *serial)  		   handle GET_CONFIG requests; everything they've  		   produced since that time crashes if this command is  		   attempted :-( */ -		dbg("%s - Marking this device as unsafe for GET_CONFIG " -		    "commands", __func__); +		dev_dbg(&port->dev, +			"%s - Marking this device as unsafe for GET_CONFIG commands\n", +			__func__);  		priv->get_cfg_unsafe = !0;  	}  	return 0; -} /* cypress_earthmate_startup */ - +} -static int cypress_hidcom_startup(struct usb_serial *serial) +static int cypress_hidcom_port_probe(struct usb_serial_port *port)  {  	struct cypress_private *priv; +	int ret; -	dbg("%s", __func__); - -	if (generic_startup(serial)) { -		dbg("%s - Failed setting up port %d", __func__, -				serial->port[0]->number); -		return 1; +	ret = cypress_generic_port_probe(port); +	if (ret) { +		dev_dbg(&port->dev, "%s - Failed setting up port\n", __func__); +		return ret;  	} -	priv = usb_get_serial_port_data(serial->port[0]); +	priv = usb_get_serial_port_data(port);  	priv->chiptype = CT_CYPHIDCOM;  	return 0; -} /* cypress_hidcom_startup */ - +} -static int cypress_ca42v2_startup(struct usb_serial *serial) +static int cypress_ca42v2_port_probe(struct usb_serial_port *port)  {  	struct cypress_private *priv; +	int ret; -	dbg("%s", __func__); - -	if (generic_startup(serial)) { -		dbg("%s - Failed setting up port %d", __func__, -				serial->port[0]->number); -		return 1; +	ret = cypress_generic_port_probe(port); +	if (ret) { +		dev_dbg(&port->dev, "%s - Failed setting up port\n", __func__); +		return ret;  	} -	priv = usb_get_serial_port_data(serial->port[0]); +	priv = usb_get_serial_port_data(port);  	priv->chiptype = CT_CA42V2;  	return 0; -} /* cypress_ca42v2_startup */ - +} -static void cypress_release(struct usb_serial *serial) +static int cypress_port_remove(struct usb_serial_port *port)  {  	struct cypress_private *priv; -	dbg("%s - port %d", __func__, serial->port[0]->number); - -	/* all open ports are closed at this point */ +	priv = usb_get_serial_port_data(port); -	priv = usb_get_serial_port_data(serial->port[0]); +	kfifo_free(&priv->write_fifo); +	kfree(priv); -	if (priv) { -		kfifo_free(&priv->write_fifo); -		kfree(priv); -	} +	return 0;  } -  static int cypress_open(struct tty_struct *tty, struct usb_serial_port *port)  {  	struct cypress_private *priv = usb_get_serial_port_data(port); @@ -620,8 +584,6 @@ static int cypress_open(struct tty_struct *tty, struct usb_serial_port *port)  	unsigned long flags;  	int result = 0; -	dbg("%s - port %d", __func__, port->number); -  	if (!priv->comm_is_ok)  		return -EIO; @@ -663,7 +625,7 @@ static int cypress_open(struct tty_struct *tty, struct usb_serial_port *port)  							__func__, result);  		cypress_set_dead(port);  	} -	port->port.drain_delay = 256; +  	return result;  } /* cypress_open */ @@ -686,26 +648,17 @@ static void cypress_close(struct usb_serial_port *port)  	struct cypress_private *priv = usb_get_serial_port_data(port);  	unsigned long flags; -	dbg("%s - port %d", __func__, port->number); - -	/* writing is potentially harmful, lock must be taken */ -	mutex_lock(&port->serial->disc_mutex); -	if (port->serial->disconnected) { -		mutex_unlock(&port->serial->disc_mutex); -		return; -	}  	spin_lock_irqsave(&priv->lock, flags);  	kfifo_reset_out(&priv->write_fifo);  	spin_unlock_irqrestore(&priv->lock, flags); -	dbg("%s - stopping urbs", __func__); +	dev_dbg(&port->dev, "%s - stopping urbs\n", __func__);  	usb_kill_urb(port->interrupt_in_urb);  	usb_kill_urb(port->interrupt_out_urb);  	if (stats)  		dev_info(&port->dev, "Statistics: %d Bytes In | %d Bytes Out | %d Commands Issued\n",  			priv->bytes_in, priv->bytes_out, priv->cmd_count); -	mutex_unlock(&port->serial->disc_mutex);  } /* cypress_close */ @@ -714,7 +667,7 @@ static int cypress_write(struct tty_struct *tty, struct usb_serial_port *port,  {  	struct cypress_private *priv = usb_get_serial_port_data(port); -	dbg("%s - port %d, %d bytes", __func__, port->number, count); +	dev_dbg(&port->dev, "%s - %d bytes\n", __func__, count);  	/* line control commands, which need to be executed immediately,  	   are not put into the buffer for obvious reasons. @@ -740,18 +693,18 @@ static void cypress_send(struct usb_serial_port *port)  {  	int count = 0, result, offset, actual_size;  	struct cypress_private *priv = usb_get_serial_port_data(port); +	struct device *dev = &port->dev;  	unsigned long flags;  	if (!priv->comm_is_ok)  		return; -	dbg("%s - port %d", __func__, port->number); -	dbg("%s - interrupt out size is %d", __func__, -						port->interrupt_out_size); +	dev_dbg(dev, "%s - interrupt out size is %d\n", __func__, +		port->interrupt_out_size);  	spin_lock_irqsave(&priv->lock, flags);  	if (priv->write_urb_in_use) { -		dbg("%s - can't write, urb in use", __func__); +		dev_dbg(dev, "%s - can't write, urb in use\n", __func__);  		spin_unlock_irqrestore(&priv->lock, flags);  		return;  	} @@ -781,7 +734,7 @@ static void cypress_send(struct usb_serial_port *port)  	if (priv->cmd_ctrl) {  		priv->cmd_count++; -		dbg("%s - line control command being issued", __func__); +		dev_dbg(dev, "%s - line control command being issued\n", __func__);  		spin_unlock_irqrestore(&priv->lock, flags);  		goto send;  	} else @@ -803,7 +756,7 @@ static void cypress_send(struct usb_serial_port *port)  		port->interrupt_out_buffer[0] |= count;  	} -	dbg("%s - count is %d", __func__, count); +	dev_dbg(dev, "%s - count is %d\n", __func__, count);  send:  	spin_lock_irqsave(&priv->lock, flags); @@ -816,9 +769,8 @@ send:  		actual_size = count +  			      (priv->pkt_fmt == packet_format_1 ? 2 : 1); -	usb_serial_debug_data(debug, &port->dev, __func__, -		port->interrupt_out_size, -		port->interrupt_out_urb->transfer_buffer); +	usb_serial_debug_data(dev, __func__, port->interrupt_out_size, +			      port->interrupt_out_urb->transfer_buffer);  	usb_fill_int_urb(port->interrupt_out_urb, port->serial->dev,  		usb_sndintpipe(port->serial->dev, port->interrupt_out_endpointAddress), @@ -826,7 +778,7 @@ send:  		cypress_write_int_callback, port, priv->write_urb_interval);  	result = usb_submit_urb(port->interrupt_out_urb, GFP_ATOMIC);  	if (result) { -		dev_err(&port->dev, +		dev_err_console(port,  				"%s - failed submitting write urb, error %d\n",  							__func__, result);  		priv->write_urb_in_use = 0; @@ -853,18 +805,16 @@ static int cypress_write_room(struct tty_struct *tty)  	int room = 0;  	unsigned long flags; -	dbg("%s - port %d", __func__, port->number); -  	spin_lock_irqsave(&priv->lock, flags);  	room = kfifo_avail(&priv->write_fifo);  	spin_unlock_irqrestore(&priv->lock, flags); -	dbg("%s - returns %d", __func__, room); +	dev_dbg(&port->dev, "%s - returns %d\n", __func__, room);  	return room;  } -static int cypress_tiocmget(struct tty_struct *tty, struct file *file) +static int cypress_tiocmget(struct tty_struct *tty)  {  	struct usb_serial_port *port = tty->driver_data;  	struct cypress_private *priv = usb_get_serial_port_data(port); @@ -872,8 +822,6 @@ static int cypress_tiocmget(struct tty_struct *tty, struct file *file)  	unsigned int result = 0;  	unsigned long flags; -	dbg("%s - port %d", __func__, port->number); -  	spin_lock_irqsave(&priv->lock, flags);  	control = priv->line_control;  	status = priv->current_status; @@ -886,21 +834,19 @@ static int cypress_tiocmget(struct tty_struct *tty, struct file *file)  		| ((status & UART_RI)         ? TIOCM_RI  : 0)  		| ((status & UART_CD)         ? TIOCM_CD  : 0); -	dbg("%s - result = %x", __func__, result); +	dev_dbg(&port->dev, "%s - result = %x\n", __func__, result);  	return result;  } -static int cypress_tiocmset(struct tty_struct *tty, struct file *file, +static int cypress_tiocmset(struct tty_struct *tty,  			       unsigned int set, unsigned int clear)  {  	struct usb_serial_port *port = tty->driver_data;  	struct cypress_private *priv = usb_get_serial_port_data(port);  	unsigned long flags; -	dbg("%s - port %d", __func__, port->number); -  	spin_lock_irqsave(&priv->lock, flags);  	if (set & TIOCM_RTS)  		priv->line_control |= CONTROL_RTS; @@ -916,102 +862,54 @@ static int cypress_tiocmset(struct tty_struct *tty, struct file *file,  	return cypress_write(tty, port, NULL, 0);  } - -static int cypress_ioctl(struct tty_struct *tty, struct file *file, -					unsigned int cmd, unsigned long arg) -{ -	struct usb_serial_port *port = tty->driver_data; -	struct cypress_private *priv = usb_get_serial_port_data(port); - -	dbg("%s - port %d, cmd 0x%.4x", __func__, port->number, cmd); - -	switch (cmd) { -	/* This code comes from drivers/char/serial.c and ftdi_sio.c */ -	case TIOCMIWAIT: -		while (priv != NULL) { -			interruptible_sleep_on(&priv->delta_msr_wait); -			/* see if a signal did it */ -			if (signal_pending(current)) -				return -ERESTARTSYS; -			else { -				char diff = priv->diff_status; -				if (diff == 0) -					return -EIO; /* no change => error */ - -				/* consume all events */ -				priv->diff_status = 0; - -				/* return 0 if caller wanted to know about -				   these bits */ -				if (((arg & TIOCM_RNG) && (diff & UART_RI)) || -				    ((arg & TIOCM_DSR) && (diff & UART_DSR)) || -				    ((arg & TIOCM_CD) && (diff & UART_CD)) || -				    ((arg & TIOCM_CTS) && (diff & UART_CTS))) -					return 0; -				/* otherwise caller can't care less about what -				 * happened, and so we continue to wait for -				 * more events. -				 */ -			} -		} -		return 0; -	default: -		break; -	} -	dbg("%s - arg not supported - it was 0x%04x - check include/asm/ioctls.h", __func__, cmd); -	return -ENOIOCTLCMD; -} /* cypress_ioctl */ - -  static void cypress_set_termios(struct tty_struct *tty,  	struct usb_serial_port *port, struct ktermios *old_termios)  {  	struct cypress_private *priv = usb_get_serial_port_data(port); +	struct device *dev = &port->dev;  	int data_bits, stop_bits, parity_type, parity_enable;  	unsigned cflag, iflag;  	unsigned long flags;  	__u8 oldlines;  	int linechange = 0; -	dbg("%s - port %d", __func__, port->number); -  	spin_lock_irqsave(&priv->lock, flags);  	/* We can't clean this one up as we don't know the device type  	   early enough */  	if (!priv->termios_initialized) {  		if (priv->chiptype == CT_EARTHMATE) { -			*(tty->termios) = tty_std_termios; -			tty->termios->c_cflag = B4800 | CS8 | CREAD | HUPCL | +			tty->termios = tty_std_termios; +			tty->termios.c_cflag = B4800 | CS8 | CREAD | HUPCL |  				CLOCAL; -			tty->termios->c_ispeed = 4800; -			tty->termios->c_ospeed = 4800; +			tty->termios.c_ispeed = 4800; +			tty->termios.c_ospeed = 4800;  		} else if (priv->chiptype == CT_CYPHIDCOM) { -			*(tty->termios) = tty_std_termios; -			tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | +			tty->termios = tty_std_termios; +			tty->termios.c_cflag = B9600 | CS8 | CREAD | HUPCL |  				CLOCAL; -			tty->termios->c_ispeed = 9600; -			tty->termios->c_ospeed = 9600; +			tty->termios.c_ispeed = 9600; +			tty->termios.c_ospeed = 9600;  		} else if (priv->chiptype == CT_CA42V2) { -			*(tty->termios) = tty_std_termios; -			tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | +			tty->termios = tty_std_termios; +			tty->termios.c_cflag = B9600 | CS8 | CREAD | HUPCL |  				CLOCAL; -			tty->termios->c_ispeed = 9600; -			tty->termios->c_ospeed = 9600; +			tty->termios.c_ispeed = 9600; +			tty->termios.c_ospeed = 9600;  		}  		priv->termios_initialized = 1;  	}  	spin_unlock_irqrestore(&priv->lock, flags);  	/* Unsupported features need clearing */ -	tty->termios->c_cflag &= ~(CMSPAR|CRTSCTS); +	tty->termios.c_cflag &= ~(CMSPAR|CRTSCTS); -	cflag = tty->termios->c_cflag; -	iflag = tty->termios->c_iflag; +	cflag = tty->termios.c_cflag; +	iflag = tty->termios.c_iflag;  	/* check if there are new settings */  	if (old_termios) {  		spin_lock_irqsave(&priv->lock, flags); -		priv->tmp_termios = *(tty->termios); +		priv->tmp_termios = tty->termios;  		spin_unlock_irqrestore(&priv->lock, flags);  	} @@ -1042,23 +940,21 @@ static void cypress_set_termios(struct tty_struct *tty,  		data_bits = 3;  		break;  	default: -		dev_err(&port->dev, "%s - CSIZE was set, but not CS5-CS8\n", -			__func__); +		dev_err(dev, "%s - CSIZE was set, but not CS5-CS8\n", __func__);  		data_bits = 3;  	}  	spin_lock_irqsave(&priv->lock, flags);  	oldlines = priv->line_control;  	if ((cflag & CBAUD) == B0) {  		/* drop dtr and rts */ -		dbg("%s - dropping the lines, baud rate 0bps", __func__); +		dev_dbg(dev, "%s - dropping the lines, baud rate 0bps\n", __func__);  		priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);  	} else  		priv->line_control = (CONTROL_DTR | CONTROL_RTS);  	spin_unlock_irqrestore(&priv->lock, flags); -	dbg("%s - sending %d stop_bits, %d parity_enable, %d parity_type, " -			"%d data_bits (+5)", __func__, stop_bits, -			parity_enable, parity_type, data_bits); +	dev_dbg(dev, "%s - sending %d stop_bits, %d parity_enable, %d parity_type, %d data_bits (+5)\n", +		__func__, stop_bits, parity_enable, parity_type, data_bits);  	cypress_serial_control(tty, port, tty_get_baud_rate(tty),  			data_bits, stop_bits, @@ -1075,11 +971,10 @@ static void cypress_set_termios(struct tty_struct *tty,  	spin_lock_irqsave(&priv->lock, flags);  	if (priv->chiptype == CT_EARTHMATE && priv->baud_rate == 4800) { -		dbg("Using custom termios settings for a baud rate of " -				"4800bps."); +		dev_dbg(dev, "Using custom termios settings for a baud rate of 4800bps.\n");  		/* define custom termios settings for NMEA protocol */ -		tty->termios->c_iflag /* input modes - */ +		tty->termios.c_iflag /* input modes - */  			&= ~(IGNBRK  /* disable ignore break */  			| BRKINT     /* disable break causes interrupt */  			| PARMRK     /* disable mark parity errors */ @@ -1089,10 +984,10 @@ static void cypress_set_termios(struct tty_struct *tty,  			| ICRNL      /* disable translate CR to NL */  			| IXON);     /* disable enable XON/XOFF flow control */ -		tty->termios->c_oflag /* output modes */ +		tty->termios.c_oflag /* output modes */  			&= ~OPOST;    /* disable postprocess output char */ -		tty->termios->c_lflag /* line discipline modes */ +		tty->termios.c_lflag /* line discipline modes */  			&= ~(ECHO     /* disable echo input characters */  			| ECHONL      /* disable echo new line */  			| ICANON      /* disable erase, kill, werase, and rprnt @@ -1121,13 +1016,11 @@ static int cypress_chars_in_buffer(struct tty_struct *tty)  	int chars = 0;  	unsigned long flags; -	dbg("%s - port %d", __func__, port->number); -  	spin_lock_irqsave(&priv->lock, flags);  	chars = kfifo_len(&priv->write_fifo);  	spin_unlock_irqrestore(&priv->lock, flags); -	dbg("%s - returns %d", __func__, chars); +	dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars);  	return chars;  } @@ -1137,8 +1030,6 @@ static void cypress_throttle(struct tty_struct *tty)  	struct usb_serial_port *port = tty->driver_data;  	struct cypress_private *priv = usb_get_serial_port_data(port); -	dbg("%s - port %d", __func__, port->number); -  	spin_lock_irq(&priv->lock);  	priv->rx_flags = THROTTLED;  	spin_unlock_irq(&priv->lock); @@ -1151,8 +1042,6 @@ static void cypress_unthrottle(struct tty_struct *tty)  	struct cypress_private *priv = usb_get_serial_port_data(port);  	int actually_throttled, result; -	dbg("%s - port %d", __func__, port->number); -  	spin_lock_irq(&priv->lock);  	actually_throttled = priv->rx_flags & ACTUALLY_THROTTLED;  	priv->rx_flags = 0; @@ -1162,8 +1051,6 @@ static void cypress_unthrottle(struct tty_struct *tty)  		return;  	if (actually_throttled) { -		port->interrupt_in_urb->dev = port->serial->dev; -  		result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);  		if (result) {  			dev_err(&port->dev, "%s - failed submitting read urb, " @@ -1178,6 +1065,7 @@ static void cypress_read_int_callback(struct urb *urb)  {  	struct usb_serial_port *port = urb->context;  	struct cypress_private *priv = usb_get_serial_port_data(port); +	struct device *dev = &urb->dev->dev;  	struct tty_struct *tty;  	unsigned char *data = urb->transfer_buffer;  	unsigned long flags; @@ -1188,8 +1076,6 @@ static void cypress_read_int_callback(struct urb *urb)  	int i = 0;  	int status = urb->status; -	dbg("%s - port %d", __func__, port->number); -  	switch (status) {  	case 0: /* success */  		break; @@ -1203,16 +1089,15 @@ static void cypress_read_int_callback(struct urb *urb)  		/* FALLS THROUGH */  	default:  		/* something ugly is going on... */ -		dev_err(&urb->dev->dev, -			"%s - unexpected nonzero read status received: %d\n", -							__func__, status); +		dev_err(dev, "%s - unexpected nonzero read status received: %d\n", +			__func__, status);  		cypress_set_dead(port);  		return;  	}  	spin_lock_irqsave(&priv->lock, flags);  	if (priv->rx_flags & THROTTLED) { -		dbg("%s - now throttling", __func__); +		dev_dbg(dev, "%s - now throttling\n", __func__);  		priv->rx_flags |= ACTUALLY_THROTTLED;  		spin_unlock_irqrestore(&priv->lock, flags);  		return; @@ -1221,7 +1106,7 @@ static void cypress_read_int_callback(struct urb *urb)  	tty = tty_port_tty_get(&port->port);  	if (!tty) { -		dbg("%s - bad tty pointer - exiting", __func__); +		dev_dbg(dev, "%s - bad tty pointer - exiting\n", __func__);  		return;  	} @@ -1248,29 +1133,41 @@ static void cypress_read_int_callback(struct urb *urb)  	}  	spin_unlock_irqrestore(&priv->lock, flags);  	if (result < bytes) { -		dbg("%s - wrong packet size - received %d bytes but packet " -		    "said %d bytes", __func__, result, bytes); +		dev_dbg(dev, +			"%s - wrong packet size - received %d bytes but packet said %d bytes\n", +			__func__, result, bytes);  		goto continue_read;  	} -	usb_serial_debug_data(debug, &port->dev, __func__, -						urb->actual_length, data); +	usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data);  	spin_lock_irqsave(&priv->lock, flags);  	/* check to see if status has changed */  	if (priv->current_status != priv->prev_status) { -		priv->diff_status |= priv->current_status ^ -			priv->prev_status; -		wake_up_interruptible(&priv->delta_msr_wait); +		u8 delta = priv->current_status ^ priv->prev_status; + +		if (delta & UART_MSR_MASK) { +			if (delta & UART_CTS) +				port->icount.cts++; +			if (delta & UART_DSR) +				port->icount.dsr++; +			if (delta & UART_RI) +				port->icount.rng++; +			if (delta & UART_CD) +				port->icount.dcd++; + +			wake_up_interruptible(&port->port.delta_msr_wait); +		} +  		priv->prev_status = priv->current_status;  	}  	spin_unlock_irqrestore(&priv->lock, flags);  	/* hangup, as defined in acm.c... this might be a bad place for it  	 * though */ -	if (tty && !(tty->termios->c_cflag & CLOCAL) && +	if (tty && !(tty->termios.c_cflag & CLOCAL) &&  			!(priv->current_status & UART_CD)) { -		dbg("%s - calling hangup", __func__); +		dev_dbg(dev, "%s - calling hangup\n", __func__);  		tty_hangup(tty);  		goto continue_read;  	} @@ -1283,15 +1180,15 @@ static void cypress_read_int_callback(struct urb *urb)  	if (priv->current_status & CYP_ERROR) {  		spin_unlock_irqrestore(&priv->lock, flags);  		tty_flag = TTY_PARITY; -		dbg("%s - Parity Error detected", __func__); +		dev_dbg(dev, "%s - Parity Error detected\n", __func__);  	} else  		spin_unlock_irqrestore(&priv->lock, flags);  	/* process read if there is data other than line status */ -	if (tty && bytes > i) { -		tty_insert_flip_string_fixed_flag(tty, data + i, +	if (bytes > i) { +		tty_insert_flip_string_fixed_flag(&port->port, data + i,  				tty_flag, bytes - i); -		tty_flip_buffer_push(tty); +		tty_flip_buffer_push(&port->port);  	}  	spin_lock_irqsave(&priv->lock, flags); @@ -1314,9 +1211,8 @@ continue_read:  				priv->read_urb_interval);  		result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);  		if (result && result != -EPERM) { -			dev_err(&urb->dev->dev, "%s - failed resubmitting " -					"read urb, error %d\n", __func__, -					result); +			dev_err(dev, "%s - failed resubmitting read urb, error %d\n", +				__func__, result);  			cypress_set_dead(port);  		}  	} @@ -1327,11 +1223,9 @@ static void cypress_write_int_callback(struct urb *urb)  {  	struct usb_serial_port *port = urb->context;  	struct cypress_private *priv = usb_get_serial_port_data(port); -	int result; +	struct device *dev = &urb->dev->dev;  	int status = urb->status; -	dbg("%s - port %d", __func__, port->number); -  	switch (status) {  	case 0:  		/* success */ @@ -1340,31 +1234,16 @@ static void cypress_write_int_callback(struct urb *urb)  	case -ENOENT:  	case -ESHUTDOWN:  		/* this urb is terminated, clean up */ -		dbg("%s - urb shutting down with status: %d", -						__func__, status); +		dev_dbg(dev, "%s - urb shutting down with status: %d\n", +			__func__, status);  		priv->write_urb_in_use = 0;  		return; -	case -EPIPE: /* no break needed; clear halt and resubmit */ -		if (!priv->comm_is_ok) -			break; -		usb_clear_halt(port->serial->dev, 0x02); -		/* error in the urb, so we have to resubmit it */ -		dbg("%s - nonzero write bulk status received: %d", -			__func__, status); -		port->interrupt_out_urb->transfer_buffer_length = 1; -		port->interrupt_out_urb->dev = port->serial->dev; -		result = usb_submit_urb(port->interrupt_out_urb, GFP_ATOMIC); -		if (!result) -			return; -		dev_err(&urb->dev->dev, -			"%s - failed resubmitting write urb, error %d\n", -							__func__, result); -		cypress_set_dead(port); -		break; +	case -EPIPE: +		/* Cannot call usb_clear_halt while in_interrupt */ +		/* FALLTHROUGH */  	default: -		dev_err(&urb->dev->dev, -			 "%s - unexpected nonzero write status received: %d\n", -							__func__, status); +		dev_err(dev, "%s - unexpected nonzero write status received: %d\n", +			__func__, status);  		cypress_set_dead(port);  		break;  	} @@ -1374,66 +1253,12 @@ static void cypress_write_int_callback(struct urb *urb)  	cypress_send(port);  } - -/***************************************************************************** - * Module functions - *****************************************************************************/ - -static int __init cypress_init(void) -{ -	int retval; - -	dbg("%s", __func__); - -	retval = usb_serial_register(&cypress_earthmate_device); -	if (retval) -		goto failed_em_register; -	retval = usb_serial_register(&cypress_hidcom_device); -	if (retval) -		goto failed_hidcom_register; -	retval = usb_serial_register(&cypress_ca42v2_device); -	if (retval) -		goto failed_ca42v2_register; -	retval = usb_register(&cypress_driver); -	if (retval) -		goto failed_usb_register; - -	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" -	       DRIVER_DESC "\n"); -	return 0; - -failed_usb_register: -	usb_serial_deregister(&cypress_ca42v2_device); -failed_ca42v2_register: -	usb_serial_deregister(&cypress_hidcom_device); -failed_hidcom_register: -	usb_serial_deregister(&cypress_earthmate_device); -failed_em_register: -	return retval; -} - - -static void __exit cypress_exit(void) -{ -	dbg("%s", __func__); - -	usb_deregister(&cypress_driver); -	usb_serial_deregister(&cypress_earthmate_device); -	usb_serial_deregister(&cypress_hidcom_device); -	usb_serial_deregister(&cypress_ca42v2_device); -} - - -module_init(cypress_init); -module_exit(cypress_exit); +module_usb_serial_driver(serial_drivers, id_table_combined);  MODULE_AUTHOR(DRIVER_AUTHOR);  MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION(DRIVER_VERSION);  MODULE_LICENSE("GPL"); -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not");  module_param(stats, bool, S_IRUGO | S_IWUSR);  MODULE_PARM_DESC(stats, "Enable statistics or not");  module_param(interval, int, S_IRUGO | S_IWUSR);  | 
