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:
Родитель
9685a59a2b
Коммит
b4072f46e5
|
@ -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);
|
||||
|
|
Загрузка…
Ссылка в новой задаче