USB: garmin_gps support for new generation of gps receivers

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>
This commit is contained in:
Hermann Kneissel 2006-07-11 19:41:33 +02:00 committed by Greg Kroah-Hartman
parent 3bea733ab2
commit eb6d8c2d14

View File

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