USB: garmin_gps: removes usb_reset_device from garmin_close

The following patch removes the call to usb_reset_device which may occur
when closing the driver by implementing a new session initialization
code based on the method used by gpsbabel.

The patch is against  linux-2.6.30-rc3-git1.

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 2009-04-26 22:42:04 +02:00 коммит произвёл Greg Kroah-Hartman
Родитель 9685a59a2b
Коммит b4072f46e5
1 изменённых файлов: 73 добавлений и 125 удалений

Просмотреть файл

@ -1,7 +1,7 @@
/*
* Garmin GPS driver
*
* Copyright (C) 2006,2007 Hermann Kneissel herkne@users.sourceforge.net
* Copyright (C) 2006-2009 Hermann Kneissel herkne@users.sourceforge.net
*
* 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 31
#define VERSION_MINOR 33
#define _STR(s) #s
#define _DRIVER_VERSION(a, b) "v" _STR(a) "." _STR(b)
@ -129,7 +129,6 @@ struct garmin_data {
__u8 state;
__u16 flags;
__u8 mode;
__u8 ignorePkts;
__u8 count;
__u8 pkt_id;
__u32 serial_num;
@ -141,8 +140,6 @@ struct garmin_data {
__u8 inbuffer [GPS_IN_BUFSIZ]; /* tty -> usb */
__u8 outbuffer[GPS_OUT_BUFSIZ]; /* usb -> tty */
__u8 privpkt[4*6];
atomic_t req_count;
atomic_t resp_count;
spinlock_t lock;
struct list_head pktlist;
};
@ -170,6 +167,8 @@ struct garmin_data {
#define FLAGS_BULK_IN_ACTIVE 0x0020
#define FLAGS_BULK_IN_RESTART 0x0010
#define FLAGS_THROTTLED 0x0008
#define APP_REQ_SEEN 0x0004
#define APP_RESP_SEEN 0x0002
#define CLEAR_HALT_REQUIRED 0x0001
#define FLAGS_QUEUING 0x0100
@ -184,20 +183,16 @@ struct garmin_data {
/* function prototypes */
static void gsp_next_packet(struct garmin_data *garmin_data_p);
static int garmin_write_bulk(struct usb_serial_port *port,
static int gsp_next_packet(struct garmin_data *garmin_data_p);
static int garmin_write_bulk(struct usb_serial_port *port,
const unsigned char *buf, int count,
int dismiss_ack);
/* some special packets to be send or received */
static unsigned char const GARMIN_START_SESSION_REQ[]
= { 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0 };
static unsigned char const GARMIN_START_SESSION_REQ2[]
= { 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0 };
static unsigned char const GARMIN_START_SESSION_REPLY[]
= { 0, 0, 0, 0, 6, 0, 0, 0, 4, 0, 0, 0 };
static unsigned char const GARMIN_SESSION_ACTIVE_REPLY[]
= { 0, 0, 0, 0, 17, 0, 0, 0, 4, 0, 0, 0, 0, 16, 0, 0 };
static unsigned char const GARMIN_BULK_IN_AVAIL_REPLY[]
= { 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0 };
static unsigned char const GARMIN_APP_LAYER_REPLY[]
@ -233,13 +228,6 @@ static struct usb_driver garmin_driver = {
};
static inline int noResponseFromAppLayer(struct garmin_data *garmin_data_p)
{
return atomic_read(&garmin_data_p->req_count) ==
atomic_read(&garmin_data_p->resp_count);
}
static inline int getLayerId(const __u8 *usbPacket)
{
return __le32_to_cpup((__le32 *)(usbPacket));
@ -325,8 +313,11 @@ static int pkt_add(struct garmin_data *garmin_data_p,
state = garmin_data_p->state;
spin_unlock_irqrestore(&garmin_data_p->lock, flags);
dbg("%s - added: pkt: %d - %d bytes",
__func__, pkt->seq, data_length);
/* in serial mode, if someone is waiting for data from
the device, iconvert and send the next packet to tty. */
the device, convert and send the next packet to tty. */
if (result && (state == STATE_GSP_WAIT_DATA))
gsp_next_packet(garmin_data_p);
}
@ -411,7 +402,7 @@ static int gsp_send_ack(struct garmin_data *garmin_data_p, __u8 pkt_id)
/*
* called for a complete packet received from tty layer
*
* the complete packet (pkzid ... cksum) is in garmin_data_p->inbuf starting
* the complete packet (pktid ... cksum) is in garmin_data_p->inbuf starting
* at GSP_INITIAL_OFFSET.
*
* count - number of bytes in the input buffer including space reserved for
@ -501,7 +492,6 @@ static int gsp_receive(struct garmin_data *garmin_data_p,
unsigned long flags;
int offs = 0;
int ack_or_nak_seen = 0;
int i = 0;
__u8 *dest;
int size;
/* dleSeen: set if last byte read was a DLE */
@ -519,8 +509,8 @@ static int gsp_receive(struct garmin_data *garmin_data_p,
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",
__func__, dleSeen, skip, size, count);
/* dbg("%s - dle=%d skip=%d size=%d count=%d",
__func__, dleSeen, skip, size, count); */
if (size == 0)
size = GSP_INITIAL_OFFSET;
@ -568,7 +558,6 @@ static int gsp_receive(struct garmin_data *garmin_data_p,
} else if (!skip) {
if (dleSeen) {
dbg("non-masked DLE at %d - restarting", i);
size = GSP_INITIAL_OFFSET;
dleSeen = 0;
}
@ -599,19 +588,19 @@ static int gsp_receive(struct garmin_data *garmin_data_p,
else
garmin_data_p->flags &= ~FLAGS_GSP_DLESEEN;
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);
if (ack_or_nak_seen) {
if (gsp_next_packet(garmin_data_p) > 0)
garmin_data_p->state = STATE_ACTIVE;
else
garmin_data_p->state = STATE_GSP_WAIT_DATA;
}
return count;
}
/*
* Sends a usb packet to the tty
*
@ -733,29 +722,28 @@ static int gsp_send(struct garmin_data *garmin_data_p,
}
/*
* Process the next pending data packet - if there is one
*/
static void gsp_next_packet(struct garmin_data *garmin_data_p)
static int gsp_next_packet(struct garmin_data *garmin_data_p)
{
int result = 0;
struct garmin_packet *pkt = NULL;
while ((pkt = pkt_pop(garmin_data_p)) != NULL) {
dbg("%s - next pkt: %d", __func__, pkt->seq);
if (gsp_send(garmin_data_p, pkt->data, pkt->size) > 0) {
result = gsp_send(garmin_data_p, pkt->data, pkt->size);
if (result > 0) {
kfree(pkt);
return;
return result;
}
kfree(pkt);
}
return result;
}
/******************************************************************************
* garmin native mode
******************************************************************************/
@ -888,14 +876,6 @@ 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;
if (port != NULL && atomic_read(&garmin_data_p->resp_count)) {
/* send a terminate command */
status = garmin_write_bulk(port, GARMIN_STOP_TRANSFER_REQ,
sizeof(GARMIN_STOP_TRANSFER_REQ), 1);
}
/* flush all queued data */
pkt_clear(garmin_data_p);
@ -908,16 +888,12 @@ 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;
int i = 0;
if (status == 0) {
usb_kill_urb(port->interrupt_in_urb);
@ -931,30 +907,25 @@ static int garmin_init_session(struct usb_serial_port *port)
__func__, status);
}
/*
* using the initialization method from gpsbabel. See comments in
* gpsbabel/jeeps/gpslibusb.c gusb_reset_toggles()
*/
if (status == 0) {
dbg("%s - starting session ...", __func__);
garmin_data_p->state = STATE_ACTIVE;
status = garmin_write_bulk(port, GARMIN_START_SESSION_REQ,
for (i = 0; i < 3; i++) {
status = garmin_write_bulk(port,
GARMIN_START_SESSION_REQ,
sizeof(GARMIN_START_SESSION_REQ), 0);
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,
GARMIN_START_SESSION_REQ2,
sizeof(GARMIN_START_SESSION_REQ2), 0);
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);
}
if (status < 0)
break;
}
if (status > 0)
status = 0;
}
return status;
@ -962,8 +933,6 @@ static int garmin_init_session(struct usb_serial_port *port)
static int garmin_open(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp)
{
@ -977,8 +946,6 @@ static int garmin_open(struct tty_struct *tty,
garmin_data_p->mode = initial_mode;
garmin_data_p->count = 0;
garmin_data_p->flags = 0;
atomic_set(&garmin_data_p->req_count, 0);
atomic_set(&garmin_data_p->resp_count, 0);
spin_unlock_irqrestore(&garmin_data_p->lock, flags);
/* shutdown any bulk reads that might be going on */
@ -1006,6 +973,7 @@ static void garmin_close(struct usb_serial_port *port)
return;
mutex_lock(&port->serial->disc_mutex);
if (!port->serial->disconnected)
garmin_clear(garmin_data_p);
@ -1013,25 +981,17 @@ static void garmin_close(struct usb_serial_port *port)
usb_kill_urb(port->read_urb);
usb_kill_urb(port->write_urb);
if (!port->serial->disconnected) {
if (noResponseFromAppLayer(garmin_data_p) ||
((garmin_data_p->flags & CLEAR_HALT_REQUIRED) != 0)) {
process_resetdev_request(port);
garmin_data_p->state = STATE_RESET;
} else {
garmin_data_p->state = STATE_DISCONNECTED;
}
} else {
/* keep reset state so we know that we must start a new session */
if (garmin_data_p->state != STATE_RESET)
garmin_data_p->state = STATE_DISCONNECTED;
}
mutex_unlock(&port->serial->disc_mutex);
}
static void garmin_write_bulk_callback(struct urb *urb)
{
unsigned long flags;
struct usb_serial_port *port = urb->context;
int status = urb->status;
if (port) {
struct garmin_data *garmin_data_p =
@ -1039,20 +999,13 @@ static void garmin_write_bulk_callback(struct urb *urb)
dbg("%s - port %d", __func__, port->number);
if (GARMIN_LAYERID_APPL == getLayerId(urb->transfer_buffer)
&& (garmin_data_p->mode == MODE_GARMIN_SERIAL)) {
gsp_send_ack(garmin_data_p,
if (GARMIN_LAYERID_APPL == getLayerId(urb->transfer_buffer)) {
if (garmin_data_p->mode == MODE_GARMIN_SERIAL) {
gsp_send_ack(garmin_data_p,
((__u8 *)urb->transfer_buffer)[4]);
}
}
if (status) {
dbg("%s - nonzero write bulk status received: %d",
__func__, 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);
}
@ -1108,7 +1061,11 @@ static int garmin_write_bulk(struct usb_serial_port *port,
urb->transfer_flags |= URB_ZERO_PACKET;
if (GARMIN_LAYERID_APPL == getLayerId(buffer)) {
atomic_inc(&garmin_data_p->req_count);
spin_lock_irqsave(&garmin_data_p->lock, flags);
garmin_data_p->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;
@ -1140,6 +1097,9 @@ static int garmin_write(struct tty_struct *tty, struct usb_serial_port *port,
usb_serial_debug_data(debug, &port->dev, __func__, count, buf);
if (garmin_data_p->state == STATE_RESET)
return -EIO;
/* check for our private packets */
if (count >= GARMIN_PKTHDR_LENGTH) {
len = PRIVPKTSIZ;
@ -1184,7 +1144,7 @@ static int garmin_write(struct tty_struct *tty, struct usb_serial_port *port,
break;
case PRIV_PKTID_RESET_REQ:
atomic_inc(&garmin_data_p->req_count);
process_resetdev_request(port);
break;
case PRIV_PKTID_SET_DEF_MODE:
@ -1200,8 +1160,6 @@ static int garmin_write(struct tty_struct *tty, 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 */
@ -1224,31 +1182,33 @@ 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 long flags;
if (garmin_data_p->flags & FLAGS_DROP_DATA) {
/* abort-transfer cmd is actice */
dbg("%s - pkt dropped", __func__);
} else if (garmin_data_p->state != STATE_DISCONNECTED &&
garmin_data_p->state != STATE_RESET) {
/* remember any appl.layer packets, so we know
if a reset is required or not when closing
the device */
if (0 == memcmp(data, GARMIN_APP_LAYER_REPLY,
sizeof(GARMIN_APP_LAYER_REPLY))) {
atomic_inc(&garmin_data_p->resp_count);
}
/* if throttling is active or postprecessing is required
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);
} else if (garmin_data_p->mode == MODE_GARMIN_SERIAL) {
if (getLayerId(data) == GARMIN_LAYERID_APPL)
} else if (getLayerId(data) == GARMIN_LAYERID_APPL) {
spin_lock_irqsave(&garmin_data_p->lock, flags);
garmin_data_p->flags |= APP_RESP_SEEN;
spin_unlock_irqrestore(&garmin_data_p->lock, flags);
if (garmin_data_p->mode == MODE_GARMIN_SERIAL) {
pkt_add(garmin_data_p, data, data_length);
} else {
send_to_tty(garmin_data_p->port, data, data_length);
} else {
send_to_tty(garmin_data_p->port, data,
data_length);
}
}
/* ignore system layer packets ... */
}
}
@ -1363,8 +1323,6 @@ static void garmin_read_int_callback(struct urb *urb)
} 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);
}
@ -1391,17 +1349,7 @@ static void garmin_read_int_callback(struct urb *urb)
__func__, garmin_data_p->serial_num);
}
if (garmin_data_p->ignorePkts) {
/* this reply belongs to a request generated by the driver,
ignore it. */
dbg("%s - pkt ignored (%d)",
__func__, 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);
}
garmin_read_process(garmin_data_p, data, urb->actual_length);
port->interrupt_in_urb->dev = port->serial->dev;
retval = usb_submit_urb(urb, GFP_ATOMIC);