USB: gamin_gps: Fix for data transfer problems in native mode
Hermann Kneissel [Fri, 29 Apr 2011 06:58:43 +0000 (08:58 +0200)]
This patch fixes a problem where data received from the gps is sometimes
transferred incompletely to the serial port. If used in native mode now
all data received via the bulk queue will be forwarded to the serial
port.

Signed-off-by: Hermann Kneissel <herkne@gmx.de>
Cc: stable <stable@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

drivers/usb/serial/garmin_gps.c

index 26710b1..b0a7a9e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Garmin GPS driver
  *
- * Copyright (C) 2006-2009 Hermann Kneissel herkne@users.sourceforge.net
+ * Copyright (C) 2006-2011 Hermann Kneissel herkne@gmx.de
  *
  * The latest version of the driver can be found at
  * http://sourceforge.net/projects/garmin-gps/
@@ -51,7 +51,7 @@ static int debug;
  */
 
 #define VERSION_MAJOR  0
-#define VERSION_MINOR  33
+#define VERSION_MINOR  36
 
 #define _STR(s) #s
 #define _DRIVER_VERSION(a, b) "v" _STR(a) "." _STR(b)
@@ -410,6 +410,7 @@ static int gsp_send_ack(struct garmin_data *garmin_data_p, __u8 pkt_id)
  */
 static int gsp_rec_packet(struct garmin_data *garmin_data_p, int count)
 {
+       unsigned long flags;
        const __u8 *recpkt = garmin_data_p->inbuffer+GSP_INITIAL_OFFSET;
        __le32 *usbdata = (__le32 *) garmin_data_p->inbuffer;
 
@@ -458,7 +459,9 @@ static int gsp_rec_packet(struct garmin_data *garmin_data_p, int count)
        /* if this was an abort-transfer command, flush all
           queued data. */
        if (isAbortTrfCmnd(garmin_data_p->inbuffer)) {
+               spin_lock_irqsave(&garmin_data_p->lock, flags);
                garmin_data_p->flags |= FLAGS_DROP_DATA;
+               spin_unlock_irqrestore(&garmin_data_p->lock, flags);
                pkt_clear(garmin_data_p);
        }
 
@@ -943,7 +946,7 @@ static int garmin_open(struct tty_struct *tty, struct usb_serial_port *port)
        spin_lock_irqsave(&garmin_data_p->lock, flags);
        garmin_data_p->mode  = initial_mode;
        garmin_data_p->count = 0;
-       garmin_data_p->flags = 0;
+       garmin_data_p->flags &= FLAGS_SESSION_REPLY1_SEEN;
        spin_unlock_irqrestore(&garmin_data_p->lock, flags);
 
        /* shutdown any bulk reads that might be going on */
@@ -1178,7 +1181,8 @@ static int garmin_write_room(struct tty_struct *tty)
 
 
 static void garmin_read_process(struct garmin_data *garmin_data_p,
-                                unsigned char *data, unsigned data_length)
+                                unsigned char *data, unsigned data_length,
+                                int bulk_data)
 {
        unsigned long flags;
 
@@ -1193,7 +1197,8 @@ static void garmin_read_process(struct garmin_data *garmin_data_p,
                   send it directly to the tty port */
                if (garmin_data_p->flags & FLAGS_QUEUING) {
                        pkt_add(garmin_data_p, data, data_length);
-               } else if (getLayerId(data) == GARMIN_LAYERID_APPL) {
+               } else if (bulk_data || 
+                          getLayerId(data) == GARMIN_LAYERID_APPL) {
 
                        spin_lock_irqsave(&garmin_data_p->lock, flags);
                        garmin_data_p->flags |= APP_RESP_SEEN;
@@ -1237,7 +1242,7 @@ static void garmin_read_bulk_callback(struct urb *urb)
        usb_serial_debug_data(debug, &port->dev,
                                __func__, urb->actual_length, data);
 
-       garmin_read_process(garmin_data_p, data, urb->actual_length);
+       garmin_read_process(garmin_data_p, data, urb->actual_length, 1);
 
        if (urb->actual_length == 0 &&
                        0 != (garmin_data_p->flags & FLAGS_BULK_IN_RESTART)) {
@@ -1346,7 +1351,7 @@ static void garmin_read_int_callback(struct urb *urb)
                        __func__, garmin_data_p->serial_num);
        }
 
-       garmin_read_process(garmin_data_p, data, urb->actual_length);
+       garmin_read_process(garmin_data_p, data, urb->actual_length, 0);
 
        port->interrupt_in_urb->dev = port->serial->dev;
        retval = usb_submit_urb(urb, GFP_ATOMIC);
@@ -1461,6 +1466,7 @@ static int garmin_attach(struct usb_serial *serial)
        garmin_data_p->timer.function = timeout_handler;
        garmin_data_p->port = port;
        garmin_data_p->state = 0;
+       garmin_data_p->flags = 0;
        garmin_data_p->count = 0;
        usb_set_serial_port_data(port, garmin_data_p);