USB: garmin_gps support for new generation of gps receivers
authorHermann Kneissel <hermann.kneissel@gmx.net>
Tue, 11 Jul 2006 17:41:33 +0000 (19:41 +0200)
committerGreg Kroah-Hartman <gregkh@suse.de>
Wed, 27 Sep 2006 18:58:52 +0000 (11:58 -0700)
The attached patch adds support for the new generation of gps receivers (eg.
GPSmap 60Cx) to garmin_gps.c.

Signed-off-by: Hermann Kneissel <herkne@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/usb/serial/garmin_gps.c

index 7278526..4b1196a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Garmin GPS driver
  *
- * Copyright (C) 2004 Hermann Kneissel herkne@users.sourceforge.net
+ * Copyright (C) 2006 Hermann Kneissel herkne@users.sourceforge.net
  *
  * The latest version of the driver can be found at
  * http://sourceforge.net/projects/garmin-gps/
@@ -37,6 +37,8 @@
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
 
+#include <linux/version.h>
+
 /* the mode to be set when the port ist opened */
 static int initial_mode = 1;
 
@@ -50,7 +52,7 @@ static int debug = 0;
  */
 
 #define VERSION_MAJOR  0
-#define VERSION_MINOR  23
+#define VERSION_MINOR  28
 
 #define _STR(s) #s
 #define _DRIVER_VERSION(a,b) "v" _STR(a) "." _STR(b)
@@ -164,7 +166,8 @@ struct garmin_data {
 #define FLAGS_SESSION_REPLY1_SEEN 0x0080
 #define FLAGS_SESSION_REPLY2_SEEN 0x0040
 #define FLAGS_BULK_IN_ACTIVE      0x0020
-#define FLAGS_THROTTLED           0x0010
+#define FLAGS_BULK_IN_RESTART     0x0010
+#define FLAGS_THROTTLED           0x0008
 #define CLEAR_HALT_REQUIRED       0x0001
 
 #define FLAGS_QUEUING             0x0100
@@ -224,7 +227,7 @@ static struct usb_driver garmin_driver = {
        .probe =        usb_serial_probe,
        .disconnect =   usb_serial_disconnect,
        .id_table =     id_table,
-       .no_dynamic_id =        1,
+       .no_dynamic_id = 1,
 };
 
 
@@ -270,7 +273,7 @@ static inline int isAbortTrfCmnd(const unsigned char *buf)
 
 
 static void send_to_tty(struct usb_serial_port *port,
-                        char *data, unsigned int actual_length)
+                       char *data, unsigned int actual_length)
 {
        struct tty_struct *tty = port->tty;
 
@@ -294,15 +297,15 @@ static void send_to_tty(struct usb_serial_port *port,
  * queue a received (usb-)packet for later processing
  */
 static int pkt_add(struct garmin_data * garmin_data_p,
-                   unsigned char *data, unsigned int data_length)
+                  unsigned char *data, unsigned int data_length)
 {
+       int state = 0;
        int result = 0;
        unsigned long flags;
        struct garmin_packet *pkt;
 
        /* process only packets containg data ... */
        if (data_length) {
-               garmin_data_p->flags |= FLAGS_QUEUING;
                pkt = kmalloc(sizeof(struct garmin_packet)+data_length,
                              GFP_ATOMIC);
                if (pkt == NULL) {
@@ -313,14 +316,16 @@ static int pkt_add(struct garmin_data * garmin_data_p,
                memcpy(pkt->data, data, data_length);
 
                spin_lock_irqsave(&garmin_data_p->lock, flags);
+               garmin_data_p->flags |= FLAGS_QUEUING;
                result = list_empty(&garmin_data_p->pktlist);
                pkt->seq = garmin_data_p->seq_counter++;
                list_add_tail(&pkt->list, &garmin_data_p->pktlist);
+               state = garmin_data_p->state;
                spin_unlock_irqrestore(&garmin_data_p->lock, flags);
 
                /* in serial mode, if someone is waiting for data from
                   the device, iconvert and send the next packet to tty. */
-               if (result && (garmin_data_p->state == STATE_GSP_WAIT_DATA)) {
+               if (result && (state == STATE_GSP_WAIT_DATA)) {
                        gsp_next_packet(garmin_data_p);
                }
        }
@@ -370,9 +375,9 @@ static void pkt_clear(struct garmin_data * garmin_data_p)
 static int gsp_send_ack(struct garmin_data * garmin_data_p, __u8 pkt_id)
 {
        __u8 pkt[10];
-        __u8 cksum = 0;
-        __u8 *ptr = pkt;
-        unsigned  l = 0;
+       __u8 cksum = 0;
+       __u8 *ptr = pkt;
+       unsigned  l = 0;
 
        dbg("%s - pkt-id: 0x%X.", __FUNCTION__, 0xFF & pkt_id);
 
@@ -416,7 +421,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)
 {
        const __u8* recpkt = garmin_data_p->inbuffer+GSP_INITIAL_OFFSET;
-        __le32 *usbdata = (__le32 *) garmin_data_p->inbuffer;
+       __le32 *usbdata = (__le32 *) garmin_data_p->inbuffer;
 
        int cksum = 0;
        int n = 0;
@@ -447,11 +452,11 @@ static int gsp_rec_packet(struct garmin_data * garmin_data_p, int count)
                n++;
        }
 
-       if ((0xff & (cksum + *recpkt)) != 0) {
-                dbg("%s - invalid checksum, expected %02x, got %02x",
-                        __FUNCTION__, 0xff & -cksum, 0xff & *recpkt);
-                return -EINVPKT;
-        }
+       if ((0xff & (cksum + *recpkt)) != 0) {
+               dbg("%s - invalid checksum, expected %02x, got %02x",
+                       __FUNCTION__, 0xff & -cksum, 0xff & *recpkt);
+               return -EINVPKT;
+       }
 
        usbdata[0] = __cpu_to_le32(GARMIN_LAYERID_APPL);
        usbdata[1] = __cpu_to_le32(pktid);
@@ -491,20 +496,28 @@ static int gsp_rec_packet(struct garmin_data * garmin_data_p, int count)
  */
 
 static int gsp_receive(struct garmin_data * garmin_data_p,
-                       const unsigned char *buf, int count)
+                      const unsigned char *buf, int count)
 {
+       unsigned long flags;
        int offs = 0;
        int ack_or_nak_seen = 0;
        int i = 0;
-       __u8 *dest = garmin_data_p->inbuffer;
-       int size = garmin_data_p->insize;
+       __u8 *dest;
+       int size;
        // dleSeen: set if last byte read was a DLE
-       int dleSeen = garmin_data_p->flags & FLAGS_GSP_DLESEEN;
+       int dleSeen;
        // skip: if set, skip incoming data until possible start of
        //       new packet
-       int skip = garmin_data_p->flags & FLAGS_GSP_SKIP;
+       int skip;
        __u8 data;
 
+       spin_lock_irqsave(&garmin_data_p->lock, flags);
+       dest = garmin_data_p->inbuffer;
+       size = garmin_data_p->insize;
+       dleSeen = garmin_data_p->flags & FLAGS_GSP_DLESEEN;
+       skip = garmin_data_p->flags & FLAGS_GSP_SKIP;
+       spin_unlock_irqrestore(&garmin_data_p->lock, flags);
+
        dbg("%s - dle=%d skip=%d size=%d count=%d",
                __FUNCTION__, dleSeen, skip, size, count);
 
@@ -572,6 +585,8 @@ static int gsp_receive(struct garmin_data * garmin_data_p,
                }
        }
 
+       spin_lock_irqsave(&garmin_data_p->lock, flags);
+
        garmin_data_p->insize = size;
 
        // copy flags back to structure
@@ -587,6 +602,11 @@ static int gsp_receive(struct garmin_data * garmin_data_p,
 
        if (ack_or_nak_seen) {
                garmin_data_p->state = STATE_GSP_WAIT_DATA;
+       }
+
+       spin_unlock_irqrestore(&garmin_data_p->lock, flags);
+
+       if (ack_or_nak_seen) {
                gsp_next_packet(garmin_data_p);
        }
 
@@ -676,7 +696,7 @@ static int gsp_send(struct garmin_data * garmin_data_p,
        src = garmin_data_p->outbuffer+GARMIN_PKTHDR_LENGTH;
        if (k > (GARMIN_PKTHDR_LENGTH-2)) {
                /* can't add stuffing DLEs in place, move data to end 
-                   of buffer ... */
+                  of buffer ... */
                dst = garmin_data_p->outbuffer+GPS_OUT_BUFSIZ-datalen;
                memcpy(dst, src, datalen);
                src = dst;
@@ -755,8 +775,9 @@ static void gsp_next_packet(struct garmin_data * garmin_data_p)
  * or even incomplete packets
  */
 static int nat_receive(struct garmin_data * garmin_data_p,
-                       const unsigned char *buf, int count)
+                      const unsigned char *buf, int count)
 {
+       unsigned long flags;
        __u8 * dest;
        int offs = 0;
        int result = count;
@@ -803,7 +824,9 @@ static int nat_receive(struct garmin_data * garmin_data_p,
                                /* 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);
                                }
                        }
@@ -839,12 +862,15 @@ static void priv_status_resp(struct usb_serial_port *port)
 
 static int process_resetdev_request(struct usb_serial_port *port)
 {
+       unsigned long flags;
        int status;
        struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
 
+       spin_lock_irqsave(&garmin_data_p->lock, flags);
        garmin_data_p->flags &= ~(CLEAR_HALT_REQUIRED);
        garmin_data_p->state = STATE_RESET;
        garmin_data_p->serial_num = 0;
+       spin_unlock_irqrestore(&garmin_data_p->lock, flags);
 
        usb_kill_urb (port->interrupt_in_urb);
        dbg("%s - usb_reset_device", __FUNCTION__ );
@@ -862,6 +888,7 @@ static int process_resetdev_request(struct usb_serial_port *port)
  */
 static int garmin_clear(struct garmin_data * garmin_data_p)
 {
+       unsigned long flags;
        int status = 0;
 
        struct usb_serial_port *port = garmin_data_p->port;
@@ -875,8 +902,10 @@ static int garmin_clear(struct garmin_data * garmin_data_p)
        /* flush all queued data */
        pkt_clear(garmin_data_p);
 
+       spin_lock_irqsave(&garmin_data_p->lock, flags);
        garmin_data_p->insize = 0;
        garmin_data_p->outsize = 0;
+       spin_unlock_irqrestore(&garmin_data_p->lock, flags);
 
        return status;
 }
@@ -888,6 +917,7 @@ static int garmin_clear(struct garmin_data * garmin_data_p)
 
 static int garmin_init_session(struct usb_serial_port *port)
 {
+       unsigned long flags;
        struct usb_serial *serial = port->serial;
        struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
        int status = 0;
@@ -913,7 +943,9 @@ static int garmin_init_session(struct usb_serial_port *port)
 
                if (status >= 0) {
 
+                       spin_lock_irqsave(&garmin_data_p->lock, flags);
                        garmin_data_p->ignorePkts++;
+                       spin_unlock_irqrestore(&garmin_data_p->lock, flags);
 
                        /* not needed, but the win32 driver does it too ... */
                        status = garmin_write_bulk(port,
@@ -921,7 +953,9 @@ static int garmin_init_session(struct usb_serial_port *port)
                                                   sizeof(GARMIN_START_SESSION_REQ2));
                        if (status >= 0) {
                                status = 0;
+                               spin_lock_irqsave(&garmin_data_p->lock, flags);
                                garmin_data_p->ignorePkts++;
+                               spin_unlock_irqrestore(&garmin_data_p->lock, flags);
                        }
                }
        }
@@ -935,6 +969,7 @@ static int garmin_init_session(struct usb_serial_port *port)
 
 static int garmin_open (struct usb_serial_port *port, struct file *filp)
 {
+       unsigned long flags;
        int status = 0;
        struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
 
@@ -948,9 +983,11 @@ static int garmin_open (struct usb_serial_port *port, struct file *filp)
        if (port->tty)
                port->tty->low_latency = 1;
 
+       spin_lock_irqsave(&garmin_data_p->lock, flags);
        garmin_data_p->mode  = initial_mode;
        garmin_data_p->count = 0;
        garmin_data_p->flags = 0;
+       spin_unlock_irqrestore(&garmin_data_p->lock, flags);
 
        /* shutdown any bulk reads that might be going on */
        usb_kill_urb (port->write_urb);
@@ -996,6 +1033,7 @@ static void garmin_close (struct usb_serial_port *port, struct file * filp)
 
 static void garmin_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
 {
+       unsigned long flags;
        struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
        struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
 
@@ -1007,7 +1045,9 @@ static void garmin_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
        if (urb->status) {
                dbg("%s - nonzero write bulk status received: %d",
                        __FUNCTION__, urb->status);
+               spin_lock_irqsave(&garmin_data_p->lock, flags);
                garmin_data_p->flags |= CLEAR_HALT_REQUIRED;
+               spin_unlock_irqrestore(&garmin_data_p->lock, flags);
        }
 
        usb_serial_port_softint(port);
@@ -1015,8 +1055,9 @@ static void garmin_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
 
 
 static int garmin_write_bulk (struct usb_serial_port *port,
-                              const unsigned char *buf, int count)
+                             const unsigned char *buf, int count)
 {
+       unsigned long flags;
        struct usb_serial *serial = port->serial;
        struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
        struct urb *urb;
@@ -1026,7 +1067,9 @@ static int garmin_write_bulk (struct usb_serial_port *port,
        dbg("%s - port %d, state %d", __FUNCTION__, port->number,
                garmin_data_p->state);
 
+       spin_lock_irqsave(&garmin_data_p->lock, flags);
        garmin_data_p->flags &= ~FLAGS_DROP_DATA;
+       spin_unlock_irqrestore(&garmin_data_p->lock, flags);
 
        buffer = kmalloc (count, GFP_ATOMIC);
        if (!buffer) {
@@ -1053,7 +1096,9 @@ static int garmin_write_bulk (struct usb_serial_port *port,
        urb->transfer_flags |= URB_ZERO_PACKET;
 
        if (GARMIN_LAYERID_APPL == getLayerId(buffer)) {
+               spin_lock_irqsave(&garmin_data_p->lock, flags);
                garmin_data_p->flags |= FLAGS_APP_REQ_SEEN;
+               spin_unlock_irqrestore(&garmin_data_p->lock, flags);
                if (garmin_data_p->mode == MODE_GARMIN_SERIAL)  {
                        pkt_clear(garmin_data_p);
                        garmin_data_p->state = STATE_GSP_WAIT_DATA;
@@ -1087,8 +1132,9 @@ static int garmin_write_bulk (struct usb_serial_port *port,
 
 
 static int garmin_write (struct usb_serial_port *port,
-                         const unsigned char *buf, int count)
+                        const unsigned char *buf, int count)
 {
+       unsigned long flags;
        int pktid, pktsiz, len;
        struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
        __le32 *privpkt = (__le32 *)garmin_data_p->privpkt;
@@ -1139,7 +1185,9 @@ static int garmin_write (struct usb_serial_port *port,
                                break;
 
                        case PRIV_PKTID_RESET_REQ:
+                               spin_lock_irqsave(&garmin_data_p->lock, flags);
                                garmin_data_p->flags |= FLAGS_APP_REQ_SEEN;
+                               spin_unlock_irqrestore(&garmin_data_p->lock, flags);
                                break;
 
                        case PRIV_PKTID_SET_DEF_MODE:
@@ -1155,6 +1203,8 @@ static int garmin_write (struct usb_serial_port *port,
                }
        }
 
+       garmin_data_p->ignorePkts = 0;
+
        if (garmin_data_p->mode == MODE_GARMIN_SERIAL) {
                return gsp_receive(garmin_data_p, buf, count);
        } else {        /* MODE_NATIVE */
@@ -1177,10 +1227,10 @@ static int garmin_chars_in_buffer (struct usb_serial_port *port)
 {
        /*
         * Report back the number of bytes currently in our input buffer.
-         * Will this lock up the driver - the buffer contains an incomplete
-         * package which will not be written to the device until it
-         * has been completed ?
-         */
+        * Will this lock up the driver - the buffer contains an incomplete
+        * package which will not be written to the device until it
+        * has been completed ?
+        */
        //struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
        //return garmin_data_p->insize;
        return 0;
@@ -1190,6 +1240,8 @@ static int garmin_chars_in_buffer (struct usb_serial_port *port)
 static void garmin_read_process(struct garmin_data * garmin_data_p,
                                 unsigned char *data, unsigned data_length)
 {
+       unsigned long flags;
+
        if (garmin_data_p->flags & FLAGS_DROP_DATA) {
                /* abort-transfer cmd is actice */
                dbg("%s - pkt dropped", __FUNCTION__);
@@ -1200,11 +1252,14 @@ static void garmin_read_process(struct garmin_data * garmin_data_p,
                   if a reset is required or not when closing
                   the device */
                if (0 == memcmp(data, GARMIN_APP_LAYER_REPLY,
-                               sizeof(GARMIN_APP_LAYER_REPLY)))
+                               sizeof(GARMIN_APP_LAYER_REPLY))) {
+                       spin_lock_irqsave(&garmin_data_p->lock, flags);
                        garmin_data_p->flags |= FLAGS_APP_RESP_SEEN;
+                       spin_unlock_irqrestore(&garmin_data_p->lock, flags);
+               }
 
                /* if throttling is active or postprecessing is required
-                  put the received data in th input queue, otherwise
+                  put the received data in the input queue, otherwise
                   send it directly to the tty port */
                if (garmin_data_p->flags & FLAGS_QUEUING) {
                        pkt_add(garmin_data_p, data, data_length);
@@ -1221,6 +1276,7 @@ static void garmin_read_process(struct garmin_data * garmin_data_p,
 
 static void garmin_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
 {
+       unsigned long flags;
        struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
        struct usb_serial *serial =  port->serial;
        struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
@@ -1245,19 +1301,30 @@ static void garmin_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
 
        garmin_read_process(garmin_data_p, data, urb->actual_length);
 
-       /* Continue trying to read until nothing more is received  */
-       if (urb->actual_length > 0) {
-               usb_fill_bulk_urb (port->read_urb, serial->dev,
-                          usb_rcvbulkpipe (serial->dev,
-                                           port->bulk_in_endpointAddress),
-                          port->read_urb->transfer_buffer,
-                          port->read_urb->transfer_buffer_length,
-                          garmin_read_bulk_callback, port);
+       if (urb->actual_length == 0 &&
+                       0 != (garmin_data_p->flags & FLAGS_BULK_IN_RESTART)) {
+               spin_lock_irqsave(&garmin_data_p->lock, flags);
+               garmin_data_p->flags &= ~FLAGS_BULK_IN_RESTART;
+               spin_unlock_irqrestore(&garmin_data_p->lock, flags);
                status = usb_submit_urb(port->read_urb, GFP_ATOMIC);
                if (status)
                        dev_err(&port->dev,
                                "%s - failed resubmitting read urb, error %d\n",
                                __FUNCTION__, status);
+       } else if (urb->actual_length > 0) {
+               /* Continue trying to read until nothing more is received  */
+               if (0 == (garmin_data_p->flags & FLAGS_THROTTLED)) {
+                       status = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+                       if (status)
+                               dev_err(&port->dev,
+                                       "%s - failed resubmitting read urb, error %d\n",
+                                       __FUNCTION__, status);
+               }
+       } else {
+               dbg("%s - end of bulk data", __FUNCTION__);
+               spin_lock_irqsave(&garmin_data_p->lock, flags);
+               garmin_data_p->flags &= ~FLAGS_BULK_IN_ACTIVE;
+               spin_unlock_irqrestore(&garmin_data_p->lock, flags);
        }
        return;
 }
@@ -1265,6 +1332,7 @@ static void garmin_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
 
 static void garmin_read_int_callback (struct urb *urb, struct pt_regs *regs)
 {
+       unsigned long flags;
        int status;
        struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
        struct usb_serial *serial = port->serial;
@@ -1297,25 +1365,41 @@ static void garmin_read_int_callback (struct urb *urb, struct pt_regs *regs)
 
                dbg("%s - bulk data available.", __FUNCTION__);
 
-               /* bulk data available */
-               usb_fill_bulk_urb (port->read_urb, serial->dev,
-                               usb_rcvbulkpipe (serial->dev,
-                               port->bulk_in_endpointAddress),
-                               port->read_urb->transfer_buffer,
-                               port->read_urb->transfer_buffer_length,
-                               garmin_read_bulk_callback, port);
-               status = usb_submit_urb(port->read_urb, GFP_KERNEL);
-               if (status) {
-                       dev_err(&port->dev,
-                               "%s - failed submitting read urb, error %d\n",
-                       __FUNCTION__, status);
+               if (0 == (garmin_data_p->flags & FLAGS_BULK_IN_ACTIVE)) {
+
+                       /* bulk data available */
+                       usb_fill_bulk_urb (port->read_urb, serial->dev,
+                                       usb_rcvbulkpipe (serial->dev,
+                                       port->bulk_in_endpointAddress),
+                                       port->read_urb->transfer_buffer,
+                                       port->read_urb->transfer_buffer_length,
+                                       garmin_read_bulk_callback, port);
+                       status = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+                       if (status) {
+                               dev_err(&port->dev,
+                                       "%s - failed submitting read urb, error %d\n",
+                               __FUNCTION__, status);
+                       } else {
+                               spin_lock_irqsave(&garmin_data_p->lock, flags);
+                               garmin_data_p->flags |= FLAGS_BULK_IN_ACTIVE;
+                               /* do not send this packet to the user */
+                               garmin_data_p->ignorePkts = 1;
+                               spin_unlock_irqrestore(&garmin_data_p->lock, flags);
+                       }
+               } else {
+                       /* bulk-in transfer still active */
+                       spin_lock_irqsave(&garmin_data_p->lock, flags);
+                       garmin_data_p->flags |= FLAGS_BULK_IN_RESTART;
+                       spin_unlock_irqrestore(&garmin_data_p->lock, flags);
                }
 
        } else if (urb->actual_length == (4+sizeof(GARMIN_START_SESSION_REPLY))
                         && 0 == memcmp(data, GARMIN_START_SESSION_REPLY,
                                        sizeof(GARMIN_START_SESSION_REPLY))) {
 
+               spin_lock_irqsave(&garmin_data_p->lock, flags);
                garmin_data_p->flags |= FLAGS_SESSION_REPLY1_SEEN;
+               spin_unlock_irqrestore(&garmin_data_p->lock, flags);
 
                /* save the serial number */
                garmin_data_p->serial_num 
@@ -1330,7 +1414,9 @@ static void garmin_read_int_callback (struct urb *urb, struct pt_regs *regs)
                   ignore it. */
                dbg("%s - pkt ignored (%d)",
                        __FUNCTION__, garmin_data_p->ignorePkts);
+               spin_lock_irqsave(&garmin_data_p->lock, flags);
                garmin_data_p->ignorePkts--;
+               spin_unlock_irqrestore(&garmin_data_p->lock, flags);
        } else {
                garmin_read_process(garmin_data_p, data, urb->actual_length);
        }
@@ -1351,18 +1437,20 @@ static void garmin_read_int_callback (struct urb *urb, struct pt_regs *regs)
  */
 static int garmin_flush_queue(struct garmin_data * garmin_data_p)
 {
+       unsigned long flags;
        struct garmin_packet *pkt;
 
        if ((garmin_data_p->flags & FLAGS_THROTTLED) == 0) {
                pkt = pkt_pop(garmin_data_p);
                if (pkt != NULL) {
-
                        send_to_tty(garmin_data_p->port, pkt->data, pkt->size);
                        kfree(pkt);
                        mod_timer(&garmin_data_p->timer, (1)+jiffies);
 
                } else {
+                       spin_lock_irqsave(&garmin_data_p->lock, flags);
                        garmin_data_p->flags &= ~FLAGS_QUEUING;
+                       spin_unlock_irqrestore(&garmin_data_p->lock, flags);
                }
        }
        return 0;
@@ -1371,26 +1459,41 @@ static int garmin_flush_queue(struct garmin_data * garmin_data_p)
 
 static void garmin_throttle (struct usb_serial_port *port)
 {
+       unsigned long flags;
        struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
 
        dbg("%s - port %d", __FUNCTION__, port->number);
        /* set flag, data received will be put into a queue
           for later processing */
+       spin_lock_irqsave(&garmin_data_p->lock, flags);
        garmin_data_p->flags |= FLAGS_QUEUING|FLAGS_THROTTLED;
+       spin_unlock_irqrestore(&garmin_data_p->lock, flags);
 }
 
 
 static void garmin_unthrottle (struct usb_serial_port *port)
 {
+       unsigned long flags;
        struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
+       int status;
 
        dbg("%s - port %d", __FUNCTION__, port->number);
+       spin_lock_irqsave(&garmin_data_p->lock, flags);
        garmin_data_p->flags &= ~FLAGS_THROTTLED;
+       spin_unlock_irqrestore(&garmin_data_p->lock, flags);
 
        /* in native mode send queued data to tty, in
           serial mode nothing needs to be done here */
        if (garmin_data_p->mode == MODE_NATIVE)
                garmin_flush_queue(garmin_data_p);
+
+       if (0 != (garmin_data_p->flags & FLAGS_BULK_IN_ACTIVE)) {
+               status = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+               if (status)
+                       dev_err(&port->dev,
+                               "%s - failed resubmitting read urb, error %d\n",
+                               __FUNCTION__, status);
+       }
 }
 
 
@@ -1420,11 +1523,12 @@ static int garmin_attach (struct usb_serial *serial)
 
        dbg("%s", __FUNCTION__);
 
-       garmin_data_p = kzalloc(sizeof(struct garmin_data), GFP_KERNEL);
+       garmin_data_p = kmalloc (sizeof(struct garmin_data), GFP_KERNEL);
        if (garmin_data_p == NULL) {
                dev_err(&port->dev, "%s - Out of memory\n", __FUNCTION__);
                return -ENOMEM;
        }
+       memset (garmin_data_p, 0, sizeof(struct garmin_data));
        init_timer(&garmin_data_p->timer);
        spin_lock_init(&garmin_data_p->lock);
        INIT_LIST_HEAD(&garmin_data_p->pktlist);
@@ -1459,10 +1563,10 @@ static void garmin_shutdown (struct usb_serial *serial)
 /* All of the device info needed */
 static struct usb_serial_driver garmin_device = {
        .driver = {
-               .owner =        THIS_MODULE,
-               .name =         "garmin_gps",
+               .owner       = THIS_MODULE,
+               .name        = "garmin_gps",
        },
-       .description =          "Garmin GPS usb/tty",
+       .description         = "Garmin GPS usb/tty",
        .id_table            = id_table,
        .num_interrupt_in    = 1,
        .num_bulk_in         = 1,
@@ -1483,6 +1587,7 @@ static struct usb_serial_driver garmin_device = {
 };
 
 
+
 static int __init garmin_init (void)
 {
        int retval;