]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/usb/serial/garmin_gps.c
USB: gamin_gps: Fix for data transfer problems in native mode
[karo-tx-linux.git] / drivers / usb / serial / garmin_gps.c
index 26710b1899185d40cdd8d797ec9968da1ff08f53..456447e03383c5b17429a89a3cf05be99af9647d 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);