public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [BUG] usb-serial / pl2302 corrupted receive
@ 2010-03-01 18:07 Peter Feuerer
  2010-03-02 23:53 ` Greg KH
  0 siblings, 1 reply; 12+ messages in thread
From: Peter Feuerer @ 2010-03-01 18:07 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: linux-kernel

Hi Greg,

I tried to flash an AVR microcontroler via an USB to serial converter which 
uses pl2302 driver. It didn't work, so I set up following test to reproduce 
the bug:

I connected two pls2302 usb-serial converters to two different usb-ports 
of my machine and connected them with a rs232-nullmodem cable to each 
other.

Terminal1:
cat /dev/ttyUSB1

Terminal2:
while true; do echo 123456789012345678901234567890 > /dev/ttyUSB0 ; done


When both usb-serial converters are plugged in, the first few lines appear 
correctly on Terminal1. Then I noticed two different bahaviors:

1) The lines on Terminal1 are corrupted like: 
"1111111111111111111111123456789012345678901234567890"

2) The lines "123456789012345678901234567890" appear correctly on Terminal1 
but when I kill the "cat" command and start it again, there's only one line 
and then no output anymore.

I verified this behavior on two different machines running the same 
kernel (version 2.6.32.9).

Additionally a calltrace is printed to dmesg (see end of mail)


I'm not 100% sure, but if I remember correctly was flashing AVR 
microcontrollers with pl2302 possible about the time when kernel 2.6.22 was 
released.

If you've got any questions I'd be pleased to help you.

best regards,
--peter;




---
[piie@deskpiie ~]$ lsusb
Bus 002 Device 013: ID 067b:2303 Prolific Technology, Inc. PL2303 Serial 
Port
Bus 002 Device 012: ID 067b:2303 Prolific Technology, Inc. PL2303 Serial 
Port




------------[ cut here ]------------
WARNING: at drivers/usb/serial/usb-serial.c:406 serial_write_room+0x74/0x80 
[usbserial]()
Hardware name: To Be Filled By O.E.M.
Modules linked in: pl2303 usbserial sha256_generic aes_i586 aes_generic cbc 
ipv6 snd_hda_codec_nvhdmi usbhid hid snd_hda_codec_via snd_seq_dummy 
snd_seq_oss snd_seq_midi_event snd_seq snd_seq_device snd_pcm_oss 
snd_mixer_oss snd_hda_intel snd_hda_codec snd_hwdep snd_pcm snd_timer 
ohci_hcd snd soundcore coretemp snd_page_alloc nvidia(P) shpchp i2c_nforce2 
ehci_hcd agpgart wmi psmouse thermal pci_hotplug i2c_core usbcore sg 
forcedeth button processor serio_raw vboxdrv evdev dm_crypt dm_mod fuse 
rtc_cmos rtc_core rtc_lib ext4 mbcache jbd2 crc16 sr_mod cdrom sd_mod 
pata_acpi ahci ata_generic libata scsi_mod
Pid: 15, comm: events/0 Tainted: P        W  2.6.32-ARCH #1
Call Trace:
 [<c104042e>] ? warn_slowpath_common+0x6e/0xb0
 [<f8c634b4>] ? serial_write_room+0x74/0x80 [usbserial]
 [<c1040483>] ? warn_slowpath_null+0x13/0x20
 [<f8c634b4>] ? serial_write_room+0x74/0x80 [usbserial]
 [<c11ddf15>] ? tty_write_room+0x15/0x20
 [<c11db6a7>] ? process_echoes+0x47/0x2b0
 [<c11dda85>] ? n_tty_receive_buf+0xe45/0x10c0
 [<c1002374>] ? __switch_to+0x184/0x190
 [<c103655b>] ? finish_task_switch+0x3b/0xa0
 [<c12b77d9>] ? schedule+0x2f9/0xa30
 [<f8e2cfea>] ? usb_autopm_do_interface+0x7a/0xe0 [usbcore]
 [<c11e023a>] ? flush_to_ldisc+0x14a/0x180
 [<c11e00f0>] ? flush_to_ldisc+0x0/0x180
 [<c1056f7f>] ? worker_thread+0x11f/0x260
 [<c105adf0>] ? autoremove_wake_function+0x0/0x40
 [<c1056e60>] ? worker_thread+0x0/0x260
 [<c105ab44>] ? kthread+0x74/0x80
 [<c105aad0>] ? kthread+0x0/0x80
 [<c1004627>] ? kernel_thread_helper+0x7/0x10
---[ end trace 4162a861717078f5 ]---
------------[ cut here ]------------


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [BUG] usb-serial / pl2302 corrupted receive
  2010-03-01 18:07 [BUG] usb-serial / pl2302 corrupted receive Peter Feuerer
@ 2010-03-02 23:53 ` Greg KH
  2010-03-03 10:47   ` peter
  2010-03-03 12:14   ` Alan Cox
  0 siblings, 2 replies; 12+ messages in thread
From: Greg KH @ 2010-03-02 23:53 UTC (permalink / raw)
  To: Peter Feuerer; +Cc: linux-kernel

On Mon, Mar 01, 2010 at 07:07:00PM +0100, Peter Feuerer wrote:
> Hi Greg,
> 
> I tried to flash an AVR microcontroler via an USB to serial
> converter which uses pl2302 driver. It didn't work, so I set up
> following test to reproduce the bug:
> 
> I connected two pls2302 usb-serial converters to two different
> usb-ports of my machine and connected them with a rs232-nullmodem
> cable to each other.
> 
> Terminal1:
> cat /dev/ttyUSB1
> 
> Terminal2:
> while true; do echo 123456789012345678901234567890 > /dev/ttyUSB0 ; done

cat and echo are known to not work well with usb to serial devices.  Can
you duplicate this with a "real" tty program like minicom or something
else?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [BUG] usb-serial / pl2302 corrupted receive
  2010-03-02 23:53 ` Greg KH
@ 2010-03-03 10:47   ` peter
  2010-03-03 14:17     ` Johan Hovold
  2010-03-03 12:14   ` Alan Cox
  1 sibling, 1 reply; 12+ messages in thread
From: peter @ 2010-03-03 10:47 UTC (permalink / raw)
  To: Greg KH; +Cc: linux-kernel

Hi Greg,

Quoting Greg KH <greg@kroah.com>:

> On Mon, Mar 01, 2010 at 07:07:00PM +0100, Peter Feuerer wrote:
>> I connected two pls2302 usb-serial converters to two different
>> usb-ports of my machine and connected them with a rs232-nullmodem
>> cable to each other.
>>
>> Terminal1:
>> cat /dev/ttyUSB1
>>
>> Terminal2:
>> while true; do echo 123456789012345678901234567890 > /dev/ttyUSB0 ; done
>
> cat and echo are known to not work well with usb to serial devices.  Can
> you duplicate this with a "real" tty program like minicom or something
> else?

I will try to set up a test use-case which uses kermit.

But there is a calltrace in kernel log when using cat & echo, so  
something in the driver went wrong.
Thus there is a bug which can be reproduced and it should be fixed,  
don't you agree?

best regards,
--peter




^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [BUG] usb-serial / pl2302 corrupted receive
  2010-03-02 23:53 ` Greg KH
  2010-03-03 10:47   ` peter
@ 2010-03-03 12:14   ` Alan Cox
  2010-03-03 14:50     ` Johan Hovold
  1 sibling, 1 reply; 12+ messages in thread
From: Alan Cox @ 2010-03-03 12:14 UTC (permalink / raw)
  To: Greg KH; +Cc: Peter Feuerer, linux-kernel

> > Terminal1:
> > cat /dev/ttyUSB1
> > 
> > Terminal2:
> > while true; do echo 123456789012345678901234567890 > /dev/ttyUSB0 ; done
> 
> cat and echo are known to not work well with usb to serial devices.  Can
> you duplicate this with a "real" tty program like minicom or something
> else?

That should no longer be the case. The kfifo buffering implementation
fixed all the broken internal buffering in the usb tty code - or should
have done.

Definitely worthy of more investigation if the second open/closes are
disrupting stuff.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [BUG] usb-serial / pl2302 corrupted receive
  2010-03-03 10:47   ` peter
@ 2010-03-03 14:17     ` Johan Hovold
  2010-03-03 18:31       ` Andreas Kemnade
  0 siblings, 1 reply; 12+ messages in thread
From: Johan Hovold @ 2010-03-03 14:17 UTC (permalink / raw)
  To: peter; +Cc: Greg KH, linux-kernel, Alan Cox, linux-usb

On Wed, Mar 03, 2010 at 11:47:05AM +0100, peter@piie.net wrote:
> Quoting Greg KH <greg@kroah.com>:
> > On Mon, Mar 01, 2010 at 07:07:00PM +0100, Peter Feuerer wrote:
> >> I connected two pls2302 usb-serial converters to two different
> >> usb-ports of my machine and connected them with a rs232-nullmodem
> >> cable to each other.
> >>
> >> Terminal1:
> >> cat /dev/ttyUSB1
> >>
> >> Terminal2:
> >> while true; do echo 123456789012345678901234567890 > /dev/ttyUSB0 ; done
> >
> > cat and echo are known to not work well with usb to serial devices.  Can
> > you duplicate this with a "real" tty program like minicom or something
> > else?
> 
> I will try to set up a test use-case which uses kermit.
> 
> But there is a calltrace in kernel log when using cat & echo, so  
> something in the driver went wrong.
> Thus there is a bug which can be reproduced and it should be fixed,  
> don't you agree?

Not necessarily. The warning you attached to your first post is a false
one (it has been fixed in 2.6.33) and is not directly related to the
problem you describe.

/Johan


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [BUG] usb-serial / pl2302 corrupted receive
  2010-03-03 12:14   ` Alan Cox
@ 2010-03-03 14:50     ` Johan Hovold
  2010-03-03 15:01       ` [PATCH] USB: pl2303: switch to generic write implementation Johan Hovold
  0 siblings, 1 reply; 12+ messages in thread
From: Johan Hovold @ 2010-03-03 14:50 UTC (permalink / raw)
  To: Alan Cox; +Cc: Greg KH, Peter Feuerer, linux-kernel

On Wed, Mar 03, 2010 at 12:14:41PM +0000, Alan Cox wrote:
> > > Terminal1:
> > > cat /dev/ttyUSB1
> > > 
> > > Terminal2:
> > > while true; do echo 123456789012345678901234567890 > /dev/ttyUSB0 ; done
> > 
> > cat and echo are known to not work well with usb to serial devices.  Can
> > you duplicate this with a "real" tty program like minicom or something
> > else?
> 
> That should no longer be the case. The kfifo buffering implementation
> fixed all the broken internal buffering in the usb tty code - or should
> have done.

Actually, the per-bulk-out-point allocated kfifo is currently unsused for most
drivers, including the pl2303.

I'm responding to this mail with a patch (against 2.6.33) which replaces
the custom fifo-based write implementation in pl2303 with the generic
kfifo based one. I've used it for quite a while now without any problems
(just haven't got around to submitting it).

If Alan's correct, this might solve the echo/cat issue, but either way
it should be applied at some point as it removes a lot of duplicate code.

/Johan


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH] USB: pl2303: switch to generic write implementation
  2010-03-03 14:50     ` Johan Hovold
@ 2010-03-03 15:01       ` Johan Hovold
  2010-03-03 15:08         ` Oliver Neukum
  0 siblings, 1 reply; 12+ messages in thread
From: Johan Hovold @ 2010-03-03 15:01 UTC (permalink / raw)
  To: linux-usb, linux-kernel; +Cc: Greg KH, Alan Cox, Peter Feuerer, Johan Hovold

Replace custom fifo-based write implementation with the generic
kfifo-based one.

Signed-off-by: Johan Hovold <jhovold@gmail.com>
---

Forgot to cc the lists...


 drivers/usb/serial/pl2303.c |  332 +------------------------------------------
 1 files changed, 4 insertions(+), 328 deletions(-)

diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index 9ec1a49..00d64db 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -40,16 +40,6 @@ static int debug;
 
 #define PL2303_CLOSING_WAIT	(30*HZ)
 
-#define PL2303_BUF_SIZE		1024
-#define PL2303_TMP_BUF_SIZE	1024
-
-struct pl2303_buf {
-	unsigned int	buf_size;
-	char		*buf_buf;
-	char		*buf_get;
-	char		*buf_put;
-};
-
 static struct usb_device_id id_table [] = {
 	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) },
 	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) },
@@ -155,173 +145,12 @@ enum pl2303_type {
 
 struct pl2303_private {
 	spinlock_t lock;
-	struct pl2303_buf *buf;
-	int write_urb_in_use;
 	wait_queue_head_t delta_msr_wait;
 	u8 line_control;
 	u8 line_status;
 	enum pl2303_type type;
 };
 
-/*
- * pl2303_buf_alloc
- *
- * Allocate a circular buffer and all associated memory.
- */
-static struct pl2303_buf *pl2303_buf_alloc(unsigned int size)
-{
-	struct pl2303_buf *pb;
-
-	if (size == 0)
-		return NULL;
-
-	pb = kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
-	if (pb == NULL)
-		return NULL;
-
-	pb->buf_buf = kmalloc(size, GFP_KERNEL);
-	if (pb->buf_buf == NULL) {
-		kfree(pb);
-		return NULL;
-	}
-
-	pb->buf_size = size;
-	pb->buf_get = pb->buf_put = pb->buf_buf;
-
-	return pb;
-}
-
-/*
- * pl2303_buf_free
- *
- * Free the buffer and all associated memory.
- */
-static void pl2303_buf_free(struct pl2303_buf *pb)
-{
-	if (pb) {
-		kfree(pb->buf_buf);
-		kfree(pb);
-	}
-}
-
-/*
- * pl2303_buf_clear
- *
- * Clear out all data in the circular buffer.
- */
-static void pl2303_buf_clear(struct pl2303_buf *pb)
-{
-	if (pb != NULL)
-		pb->buf_get = pb->buf_put;
-		/* equivalent to a get of all data available */
-}
-
-/*
- * pl2303_buf_data_avail
- *
- * Return the number of bytes of data available in the circular
- * buffer.
- */
-static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb)
-{
-	if (pb == NULL)
-		return 0;
-
-	return (pb->buf_size + pb->buf_put - pb->buf_get) % pb->buf_size;
-}
-
-/*
- * pl2303_buf_space_avail
- *
- * Return the number of bytes of space available in the circular
- * buffer.
- */
-static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb)
-{
-	if (pb == NULL)
-		return 0;
-
-	return (pb->buf_size + pb->buf_get - pb->buf_put - 1) % pb->buf_size;
-}
-
-/*
- * pl2303_buf_put
- *
- * Copy data data from a user buffer and put it into the circular buffer.
- * Restrict to the amount of space available.
- *
- * Return the number of bytes copied.
- */
-static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
-				   unsigned int count)
-{
-	unsigned int len;
-
-	if (pb == NULL)
-		return 0;
-
-	len  = pl2303_buf_space_avail(pb);
-	if (count > len)
-		count = len;
-
-	if (count == 0)
-		return 0;
-
-	len = pb->buf_buf + pb->buf_size - pb->buf_put;
-	if (count > len) {
-		memcpy(pb->buf_put, buf, len);
-		memcpy(pb->buf_buf, buf+len, count - len);
-		pb->buf_put = pb->buf_buf + count - len;
-	} else {
-		memcpy(pb->buf_put, buf, count);
-		if (count < len)
-			pb->buf_put += count;
-		else /* count == len */
-			pb->buf_put = pb->buf_buf;
-	}
-
-	return count;
-}
-
-/*
- * pl2303_buf_get
- *
- * Get data from the circular buffer and copy to the given buffer.
- * Restrict to the amount of data available.
- *
- * Return the number of bytes copied.
- */
-static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
-				   unsigned int count)
-{
-	unsigned int len;
-
-	if (pb == NULL)
-		return 0;
-
-	len = pl2303_buf_data_avail(pb);
-	if (count > len)
-		count = len;
-
-	if (count == 0)
-		return 0;
-
-	len = pb->buf_buf + pb->buf_size - pb->buf_get;
-	if (count > len) {
-		memcpy(buf, pb->buf_get, len);
-		memcpy(buf+len, pb->buf_buf, count - len);
-		pb->buf_get = pb->buf_buf + count - len;
-	} else {
-		memcpy(buf, pb->buf_get, count);
-		if (count < len)
-			pb->buf_get += count;
-		else /* count == len */
-			pb->buf_get = pb->buf_buf;
-	}
-
-	return count;
-}
-
 static int pl2303_vendor_read(__u16 value, __u16 index,
 		struct usb_serial *serial, unsigned char *buf)
 {
@@ -369,12 +198,6 @@ static int pl2303_startup(struct usb_serial *serial)
 		priv = kzalloc(sizeof(struct pl2303_private), GFP_KERNEL);
 		if (!priv)
 			goto cleanup;
-		spin_lock_init(&priv->lock);
-		priv->buf = pl2303_buf_alloc(PL2303_BUF_SIZE);
-		if (priv->buf == NULL) {
-			kfree(priv);
-			goto cleanup;
-		}
 		init_waitqueue_head(&priv->delta_msr_wait);
 		priv->type = type;
 		usb_set_serial_port_data(serial->port[i], priv);
@@ -402,7 +225,6 @@ cleanup:
 	kfree(buf);
 	for (--i; i >= 0; --i) {
 		priv = usb_get_serial_port_data(serial->port[i]);
-		pl2303_buf_free(priv->buf);
 		kfree(priv);
 		usb_set_serial_port_data(serial->port[i], NULL);
 	}
@@ -420,103 +242,6 @@ static int set_control_lines(struct usb_device *dev, u8 value)
 	return retval;
 }
 
-static void pl2303_send(struct usb_serial_port *port)
-{
-	int count, result;
-	struct pl2303_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 (priv->write_urb_in_use) {
-		spin_unlock_irqrestore(&priv->lock, flags);
-		return;
-	}
-
-	count = pl2303_buf_get(priv->buf, port->write_urb->transfer_buffer,
-			       port->bulk_out_size);
-
-	if (count == 0) {
-		spin_unlock_irqrestore(&priv->lock, flags);
-		return;
-	}
-
-	priv->write_urb_in_use = 1;
-
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	usb_serial_debug_data(debug, &port->dev, __func__, count,
-			      port->write_urb->transfer_buffer);
-
-	port->write_urb->transfer_buffer_length = count;
-	port->write_urb->dev = port->serial->dev;
-	result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
-	if (result) {
-		dev_err(&port->dev, "%s - failed submitting write urb,"
-			" error %d\n", __func__, result);
-		priv->write_urb_in_use = 0;
-		/* TODO: reschedule pl2303_send */
-	}
-
-	usb_serial_port_softint(port);
-}
-
-static int pl2303_write(struct tty_struct *tty, struct usb_serial_port *port,
-				const unsigned char *buf, int count)
-{
-	struct pl2303_private *priv = usb_get_serial_port_data(port);
-	unsigned long flags;
-
-	dbg("%s - port %d, %d bytes", __func__, port->number, count);
-
-	if (!count)
-		return count;
-
-	spin_lock_irqsave(&priv->lock, flags);
-	count = pl2303_buf_put(priv->buf, buf, count);
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	pl2303_send(port);
-
-	return count;
-}
-
-static int pl2303_write_room(struct tty_struct *tty)
-{
-	struct usb_serial_port *port = tty->driver_data;
-	struct pl2303_private *priv = usb_get_serial_port_data(port);
-	int room = 0;
-	unsigned long flags;
-
-	dbg("%s - port %d", __func__, port->number);
-
-	spin_lock_irqsave(&priv->lock, flags);
-	room = pl2303_buf_space_avail(priv->buf);
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	dbg("%s - returns %d", __func__, room);
-	return room;
-}
-
-static int pl2303_chars_in_buffer(struct tty_struct *tty)
-{
-	struct usb_serial_port *port = tty->driver_data;
-	struct pl2303_private *priv = usb_get_serial_port_data(port);
-	int chars = 0;
-	unsigned long flags;
-
-	dbg("%s - port %d", __func__, port->number);
-
-	spin_lock_irqsave(&priv->lock, flags);
-	chars = pl2303_buf_data_avail(priv->buf);
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	dbg("%s - returns %d", __func__, chars);
-	return chars;
-}
-
 static void pl2303_set_termios(struct tty_struct *tty,
 		struct usb_serial_port *port, struct ktermios *old_termios)
 {
@@ -728,15 +453,14 @@ static void pl2303_dtr_rts(struct usb_serial_port *port, int on)
 
 static void pl2303_close(struct usb_serial_port *port)
 {
-	struct pl2303_private *priv = usb_get_serial_port_data(port);
 	unsigned long flags;
 
 	dbg("%s - port %d", __func__, port->number);
 
-	spin_lock_irqsave(&priv->lock, flags);
+	spin_lock_irqsave(&port->lock, flags);
 	/* clear out any remaining data in the buffer */
-	pl2303_buf_clear(priv->buf);
-	spin_unlock_irqrestore(&priv->lock, flags);
+	kfifo_reset_out(&port->write_fifo);
+	spin_unlock_irqrestore(&port->lock, flags);
 
 	/* shutdown our urbs */
 	dbg("%s - shutting down urbs", __func__);
@@ -941,10 +665,8 @@ static void pl2303_release(struct usb_serial *serial)
 
 	for (i = 0; i < serial->num_ports; ++i) {
 		priv = usb_get_serial_port_data(serial->port[i]);
-		if (priv) {
-			pl2303_buf_free(priv->buf);
+		if (priv)
 			kfree(priv);
-		}
 	}
 }
 
@@ -1119,48 +841,6 @@ static void pl2303_read_bulk_callback(struct urb *urb)
 	return;
 }
 
-static void pl2303_write_bulk_callback(struct urb *urb)
-{
-	struct usb_serial_port *port =  urb->context;
-	struct pl2303_private *priv = usb_get_serial_port_data(port);
-	int result;
-	int status = urb->status;
-
-	dbg("%s - port %d", __func__, port->number);
-
-	switch (status) {
-	case 0:
-		/* success */
-		break;
-	case -ECONNRESET:
-	case -ENOENT:
-	case -ESHUTDOWN:
-		/* this urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d", __func__,
-		    status);
-		priv->write_urb_in_use = 0;
-		return;
-	default:
-		/* error in the urb, so we have to resubmit it */
-		dbg("%s - Overflow in write", __func__);
-		dbg("%s - nonzero write bulk status received: %d", __func__,
-		    status);
-		port->write_urb->transfer_buffer_length = 1;
-		port->write_urb->dev = port->serial->dev;
-		result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
-		if (result)
-			dev_err(&urb->dev->dev, "%s - failed resubmitting write"
-				" urb, error %d\n", __func__, result);
-		else
-			return;
-	}
-
-	priv->write_urb_in_use = 0;
-
-	/* send any buffered data */
-	pl2303_send(port);
-}
-
 /* All of the device info needed for the PL2303 SIO serial converter */
 static struct usb_serial_driver pl2303_device = {
 	.driver = {
@@ -1174,7 +854,6 @@ static struct usb_serial_driver pl2303_device = {
 	.close =		pl2303_close,
 	.dtr_rts = 		pl2303_dtr_rts,
 	.carrier_raised =	pl2303_carrier_raised,
-	.write =		pl2303_write,
 	.ioctl =		pl2303_ioctl,
 	.break_ctl =		pl2303_break_ctl,
 	.set_termios =		pl2303_set_termios,
@@ -1182,9 +861,6 @@ static struct usb_serial_driver pl2303_device = {
 	.tiocmset =		pl2303_tiocmset,
 	.read_bulk_callback =	pl2303_read_bulk_callback,
 	.read_int_callback =	pl2303_read_int_callback,
-	.write_bulk_callback =	pl2303_write_bulk_callback,
-	.write_room =		pl2303_write_room,
-	.chars_in_buffer =	pl2303_chars_in_buffer,
 	.attach =		pl2303_startup,
 	.release =		pl2303_release,
 };
-- 
1.7.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH] USB: pl2303: switch to generic write implementation
  2010-03-03 15:01       ` [PATCH] USB: pl2303: switch to generic write implementation Johan Hovold
@ 2010-03-03 15:08         ` Oliver Neukum
  2010-03-04 11:12           ` [PATCH v2] " Johan Hovold
  0 siblings, 1 reply; 12+ messages in thread
From: Oliver Neukum @ 2010-03-03 15:08 UTC (permalink / raw)
  To: Johan Hovold; +Cc: linux-usb, linux-kernel, Greg KH, Alan Cox, Peter Feuerer

Am Mittwoch, 3. März 2010 16:01:33 schrieb Johan Hovold:
> @@ -941,10 +665,8 @@ static void pl2303_release(struct usb_serial *serial)
>  
>         for (i = 0; i < serial->num_ports; ++i) {
>                 priv = usb_get_serial_port_data(serial->port[i]);
> -               if (priv) {
> -                       pl2303_buf_free(priv->buf);
> +               if (priv)
>                         kfree(priv);
> -               }
>         }
>  }

No need to test for NULL.

	Regards
		Oliver

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [BUG] usb-serial / pl2302 corrupted receive
  2010-03-03 14:17     ` Johan Hovold
@ 2010-03-03 18:31       ` Andreas Kemnade
  0 siblings, 0 replies; 12+ messages in thread
From: Andreas Kemnade @ 2010-03-03 18:31 UTC (permalink / raw)
  To: Johan Hovold; +Cc: peter, Greg KH, linux-kernel, linux-usb

[-- Attachment #1: Type: text/plain, Size: 1501 bytes --]

Hi,

On Wed, 3 Mar 2010 15:17:18 +0100
Johan Hovold <jhovold@gmail.com> wrote:

> On Wed, Mar 03, 2010 at 11:47:05AM +0100, peter@piie.net wrote:
> > Quoting Greg KH <greg@kroah.com>:
> > > On Mon, Mar 01, 2010 at 07:07:00PM +0100, Peter Feuerer wrote:
> > >> I connected two pls2302 usb-serial converters to two different
> > >> usb-ports of my machine and connected them with a rs232-nullmodem
> > >> cable to each other.
> > >>
> > >> Terminal1:
> > >> cat /dev/ttyUSB1
> > >>
> > >> Terminal2:
> > >> while true; do echo 123456789012345678901234567890 > /dev/ttyUSB0 ; done
> > >
> > > cat and echo are known to not work well with usb to serial devices.  Can
> > > you duplicate this with a "real" tty program like minicom or something
> > > else?
> > 
> > I will try to set up a test use-case which uses kermit.
> > 
> > But there is a calltrace in kernel log when using cat & echo, so  
> > something in the driver went wrong.
> > Thus there is a bug which can be reproduced and it should be fixed,  
> > don't you agree?
> 
> Not necessarily. The warning you attached to your first post is a false
> one (it has been fixed in 2.6.33) and is not directly related to the
> problem you describe.
> 
Are udev rules around which attach gpsd to the usb to serial adapter?
That might interfere.
I had problems with pl2302 adaptors due to that reason. I wondered why
stty -F /dev/ttyUSBx showed different things than on earlier calls.

Greetings
Andreas Kemnade

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 197 bytes --]

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH v2] USB: pl2303: switch to generic write implementation
  2010-03-03 15:08         ` Oliver Neukum
@ 2010-03-04 11:12           ` Johan Hovold
  2010-03-15 23:20             ` Greg KH
  0 siblings, 1 reply; 12+ messages in thread
From: Johan Hovold @ 2010-03-04 11:12 UTC (permalink / raw)
  To: Greg KH
  Cc: linux-usb, linux-kernel, Alan Cox, Peter Feuerer, Johan Hovold,
	Oliver Neukum

Replace custom fifo-based write implementation with the generic
kfifo-based one.

Signed-off-by: Johan Hovold <jhovold@gmail.com>
---

Removed redundant null check as suggested by Oliver Neukum.

Thanks,
Johan


 drivers/usb/serial/pl2303.c |  333 +------------------------------------------
 1 files changed, 4 insertions(+), 329 deletions(-)

diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index 9ec1a49..0af33cd 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -40,16 +40,6 @@ static int debug;
 
 #define PL2303_CLOSING_WAIT	(30*HZ)
 
-#define PL2303_BUF_SIZE		1024
-#define PL2303_TMP_BUF_SIZE	1024
-
-struct pl2303_buf {
-	unsigned int	buf_size;
-	char		*buf_buf;
-	char		*buf_get;
-	char		*buf_put;
-};
-
 static struct usb_device_id id_table [] = {
 	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) },
 	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) },
@@ -155,173 +145,12 @@ enum pl2303_type {
 
 struct pl2303_private {
 	spinlock_t lock;
-	struct pl2303_buf *buf;
-	int write_urb_in_use;
 	wait_queue_head_t delta_msr_wait;
 	u8 line_control;
 	u8 line_status;
 	enum pl2303_type type;
 };
 
-/*
- * pl2303_buf_alloc
- *
- * Allocate a circular buffer and all associated memory.
- */
-static struct pl2303_buf *pl2303_buf_alloc(unsigned int size)
-{
-	struct pl2303_buf *pb;
-
-	if (size == 0)
-		return NULL;
-
-	pb = kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
-	if (pb == NULL)
-		return NULL;
-
-	pb->buf_buf = kmalloc(size, GFP_KERNEL);
-	if (pb->buf_buf == NULL) {
-		kfree(pb);
-		return NULL;
-	}
-
-	pb->buf_size = size;
-	pb->buf_get = pb->buf_put = pb->buf_buf;
-
-	return pb;
-}
-
-/*
- * pl2303_buf_free
- *
- * Free the buffer and all associated memory.
- */
-static void pl2303_buf_free(struct pl2303_buf *pb)
-{
-	if (pb) {
-		kfree(pb->buf_buf);
-		kfree(pb);
-	}
-}
-
-/*
- * pl2303_buf_clear
- *
- * Clear out all data in the circular buffer.
- */
-static void pl2303_buf_clear(struct pl2303_buf *pb)
-{
-	if (pb != NULL)
-		pb->buf_get = pb->buf_put;
-		/* equivalent to a get of all data available */
-}
-
-/*
- * pl2303_buf_data_avail
- *
- * Return the number of bytes of data available in the circular
- * buffer.
- */
-static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb)
-{
-	if (pb == NULL)
-		return 0;
-
-	return (pb->buf_size + pb->buf_put - pb->buf_get) % pb->buf_size;
-}
-
-/*
- * pl2303_buf_space_avail
- *
- * Return the number of bytes of space available in the circular
- * buffer.
- */
-static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb)
-{
-	if (pb == NULL)
-		return 0;
-
-	return (pb->buf_size + pb->buf_get - pb->buf_put - 1) % pb->buf_size;
-}
-
-/*
- * pl2303_buf_put
- *
- * Copy data data from a user buffer and put it into the circular buffer.
- * Restrict to the amount of space available.
- *
- * Return the number of bytes copied.
- */
-static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
-				   unsigned int count)
-{
-	unsigned int len;
-
-	if (pb == NULL)
-		return 0;
-
-	len  = pl2303_buf_space_avail(pb);
-	if (count > len)
-		count = len;
-
-	if (count == 0)
-		return 0;
-
-	len = pb->buf_buf + pb->buf_size - pb->buf_put;
-	if (count > len) {
-		memcpy(pb->buf_put, buf, len);
-		memcpy(pb->buf_buf, buf+len, count - len);
-		pb->buf_put = pb->buf_buf + count - len;
-	} else {
-		memcpy(pb->buf_put, buf, count);
-		if (count < len)
-			pb->buf_put += count;
-		else /* count == len */
-			pb->buf_put = pb->buf_buf;
-	}
-
-	return count;
-}
-
-/*
- * pl2303_buf_get
- *
- * Get data from the circular buffer and copy to the given buffer.
- * Restrict to the amount of data available.
- *
- * Return the number of bytes copied.
- */
-static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
-				   unsigned int count)
-{
-	unsigned int len;
-
-	if (pb == NULL)
-		return 0;
-
-	len = pl2303_buf_data_avail(pb);
-	if (count > len)
-		count = len;
-
-	if (count == 0)
-		return 0;
-
-	len = pb->buf_buf + pb->buf_size - pb->buf_get;
-	if (count > len) {
-		memcpy(buf, pb->buf_get, len);
-		memcpy(buf+len, pb->buf_buf, count - len);
-		pb->buf_get = pb->buf_buf + count - len;
-	} else {
-		memcpy(buf, pb->buf_get, count);
-		if (count < len)
-			pb->buf_get += count;
-		else /* count == len */
-			pb->buf_get = pb->buf_buf;
-	}
-
-	return count;
-}
-
 static int pl2303_vendor_read(__u16 value, __u16 index,
 		struct usb_serial *serial, unsigned char *buf)
 {
@@ -369,12 +198,6 @@ static int pl2303_startup(struct usb_serial *serial)
 		priv = kzalloc(sizeof(struct pl2303_private), GFP_KERNEL);
 		if (!priv)
 			goto cleanup;
-		spin_lock_init(&priv->lock);
-		priv->buf = pl2303_buf_alloc(PL2303_BUF_SIZE);
-		if (priv->buf == NULL) {
-			kfree(priv);
-			goto cleanup;
-		}
 		init_waitqueue_head(&priv->delta_msr_wait);
 		priv->type = type;
 		usb_set_serial_port_data(serial->port[i], priv);
@@ -402,7 +225,6 @@ cleanup:
 	kfree(buf);
 	for (--i; i >= 0; --i) {
 		priv = usb_get_serial_port_data(serial->port[i]);
-		pl2303_buf_free(priv->buf);
 		kfree(priv);
 		usb_set_serial_port_data(serial->port[i], NULL);
 	}
@@ -420,103 +242,6 @@ static int set_control_lines(struct usb_device *dev, u8 value)
 	return retval;
 }
 
-static void pl2303_send(struct usb_serial_port *port)
-{
-	int count, result;
-	struct pl2303_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 (priv->write_urb_in_use) {
-		spin_unlock_irqrestore(&priv->lock, flags);
-		return;
-	}
-
-	count = pl2303_buf_get(priv->buf, port->write_urb->transfer_buffer,
-			       port->bulk_out_size);
-
-	if (count == 0) {
-		spin_unlock_irqrestore(&priv->lock, flags);
-		return;
-	}
-
-	priv->write_urb_in_use = 1;
-
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	usb_serial_debug_data(debug, &port->dev, __func__, count,
-			      port->write_urb->transfer_buffer);
-
-	port->write_urb->transfer_buffer_length = count;
-	port->write_urb->dev = port->serial->dev;
-	result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
-	if (result) {
-		dev_err(&port->dev, "%s - failed submitting write urb,"
-			" error %d\n", __func__, result);
-		priv->write_urb_in_use = 0;
-		/* TODO: reschedule pl2303_send */
-	}
-
-	usb_serial_port_softint(port);
-}
-
-static int pl2303_write(struct tty_struct *tty, struct usb_serial_port *port,
-				const unsigned char *buf, int count)
-{
-	struct pl2303_private *priv = usb_get_serial_port_data(port);
-	unsigned long flags;
-
-	dbg("%s - port %d, %d bytes", __func__, port->number, count);
-
-	if (!count)
-		return count;
-
-	spin_lock_irqsave(&priv->lock, flags);
-	count = pl2303_buf_put(priv->buf, buf, count);
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	pl2303_send(port);
-
-	return count;
-}
-
-static int pl2303_write_room(struct tty_struct *tty)
-{
-	struct usb_serial_port *port = tty->driver_data;
-	struct pl2303_private *priv = usb_get_serial_port_data(port);
-	int room = 0;
-	unsigned long flags;
-
-	dbg("%s - port %d", __func__, port->number);
-
-	spin_lock_irqsave(&priv->lock, flags);
-	room = pl2303_buf_space_avail(priv->buf);
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	dbg("%s - returns %d", __func__, room);
-	return room;
-}
-
-static int pl2303_chars_in_buffer(struct tty_struct *tty)
-{
-	struct usb_serial_port *port = tty->driver_data;
-	struct pl2303_private *priv = usb_get_serial_port_data(port);
-	int chars = 0;
-	unsigned long flags;
-
-	dbg("%s - port %d", __func__, port->number);
-
-	spin_lock_irqsave(&priv->lock, flags);
-	chars = pl2303_buf_data_avail(priv->buf);
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	dbg("%s - returns %d", __func__, chars);
-	return chars;
-}
-
 static void pl2303_set_termios(struct tty_struct *tty,
 		struct usb_serial_port *port, struct ktermios *old_termios)
 {
@@ -728,15 +453,14 @@ static void pl2303_dtr_rts(struct usb_serial_port *port, int on)
 
 static void pl2303_close(struct usb_serial_port *port)
 {
-	struct pl2303_private *priv = usb_get_serial_port_data(port);
 	unsigned long flags;
 
 	dbg("%s - port %d", __func__, port->number);
 
-	spin_lock_irqsave(&priv->lock, flags);
+	spin_lock_irqsave(&port->lock, flags);
 	/* clear out any remaining data in the buffer */
-	pl2303_buf_clear(priv->buf);
-	spin_unlock_irqrestore(&priv->lock, flags);
+	kfifo_reset_out(&port->write_fifo);
+	spin_unlock_irqrestore(&port->lock, flags);
 
 	/* shutdown our urbs */
 	dbg("%s - shutting down urbs", __func__);
@@ -941,10 +665,7 @@ static void pl2303_release(struct usb_serial *serial)
 
 	for (i = 0; i < serial->num_ports; ++i) {
 		priv = usb_get_serial_port_data(serial->port[i]);
-		if (priv) {
-			pl2303_buf_free(priv->buf);
-			kfree(priv);
-		}
+		kfree(priv);
 	}
 }
 
@@ -1119,48 +840,6 @@ static void pl2303_read_bulk_callback(struct urb *urb)
 	return;
 }
 
-static void pl2303_write_bulk_callback(struct urb *urb)
-{
-	struct usb_serial_port *port =  urb->context;
-	struct pl2303_private *priv = usb_get_serial_port_data(port);
-	int result;
-	int status = urb->status;
-
-	dbg("%s - port %d", __func__, port->number);
-
-	switch (status) {
-	case 0:
-		/* success */
-		break;
-	case -ECONNRESET:
-	case -ENOENT:
-	case -ESHUTDOWN:
-		/* this urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d", __func__,
-		    status);
-		priv->write_urb_in_use = 0;
-		return;
-	default:
-		/* error in the urb, so we have to resubmit it */
-		dbg("%s - Overflow in write", __func__);
-		dbg("%s - nonzero write bulk status received: %d", __func__,
-		    status);
-		port->write_urb->transfer_buffer_length = 1;
-		port->write_urb->dev = port->serial->dev;
-		result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
-		if (result)
-			dev_err(&urb->dev->dev, "%s - failed resubmitting write"
-				" urb, error %d\n", __func__, result);
-		else
-			return;
-	}
-
-	priv->write_urb_in_use = 0;
-
-	/* send any buffered data */
-	pl2303_send(port);
-}
-
 /* All of the device info needed for the PL2303 SIO serial converter */
 static struct usb_serial_driver pl2303_device = {
 	.driver = {
@@ -1174,7 +853,6 @@ static struct usb_serial_driver pl2303_device = {
 	.close =		pl2303_close,
 	.dtr_rts = 		pl2303_dtr_rts,
 	.carrier_raised =	pl2303_carrier_raised,
-	.write =		pl2303_write,
 	.ioctl =		pl2303_ioctl,
 	.break_ctl =		pl2303_break_ctl,
 	.set_termios =		pl2303_set_termios,
@@ -1182,9 +860,6 @@ static struct usb_serial_driver pl2303_device = {
 	.tiocmset =		pl2303_tiocmset,
 	.read_bulk_callback =	pl2303_read_bulk_callback,
 	.read_int_callback =	pl2303_read_int_callback,
-	.write_bulk_callback =	pl2303_write_bulk_callback,
-	.write_room =		pl2303_write_room,
-	.chars_in_buffer =	pl2303_chars_in_buffer,
 	.attach =		pl2303_startup,
 	.release =		pl2303_release,
 };
-- 
1.7.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH v2] USB: pl2303: switch to generic write implementation
  2010-03-04 11:12           ` [PATCH v2] " Johan Hovold
@ 2010-03-15 23:20             ` Greg KH
  2010-03-17  9:16               ` Johan Hovold
  0 siblings, 1 reply; 12+ messages in thread
From: Greg KH @ 2010-03-15 23:20 UTC (permalink / raw)
  To: Johan Hovold
  Cc: linux-usb, linux-kernel, Alan Cox, Peter Feuerer, Oliver Neukum

On Thu, Mar 04, 2010 at 12:12:52PM +0100, Johan Hovold wrote:
> Replace custom fifo-based write implementation with the generic
> kfifo-based one.

What kernel is this patch against?  For some reason it doesn't apply to
my tree right now :(

Care to respin it?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v2] USB: pl2303: switch to generic write implementation
  2010-03-15 23:20             ` Greg KH
@ 2010-03-17  9:16               ` Johan Hovold
  0 siblings, 0 replies; 12+ messages in thread
From: Johan Hovold @ 2010-03-17  9:16 UTC (permalink / raw)
  To: Greg KH
  Cc: Johan Hovold, linux-usb, linux-kernel, Alan Cox, Peter Feuerer,
	Oliver Neukum

On Mon, Mar 15, 2010 at 04:20:05PM -0700, Greg KH wrote:
> On Thu, Mar 04, 2010 at 12:12:52PM +0100, Johan Hovold wrote:
> > Replace custom fifo-based write implementation with the generic
> > kfifo-based one.
> 
> What kernel is this patch against?  For some reason it doesn't apply to
> my tree right now :(
 
It's against 2.6.33 (the bug report in question was against 2.6.32.9 so
I figured I'd rebase it against stable at least).

> Care to respin it?

I'll submit it along with some other patches shortly.

Thanks,
Johan


^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2010-03-17  9:17 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-03-01 18:07 [BUG] usb-serial / pl2302 corrupted receive Peter Feuerer
2010-03-02 23:53 ` Greg KH
2010-03-03 10:47   ` peter
2010-03-03 14:17     ` Johan Hovold
2010-03-03 18:31       ` Andreas Kemnade
2010-03-03 12:14   ` Alan Cox
2010-03-03 14:50     ` Johan Hovold
2010-03-03 15:01       ` [PATCH] USB: pl2303: switch to generic write implementation Johan Hovold
2010-03-03 15:08         ` Oliver Neukum
2010-03-04 11:12           ` [PATCH v2] " Johan Hovold
2010-03-15 23:20             ` Greg KH
2010-03-17  9:16               ` Johan Hovold

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox