2017-11-03 13:28:30 +03:00
// SPDX-License-Identifier: GPL-2.0+
2005-04-17 02:20:36 +04:00
/*
* Garmin GPS driver
*
2011-04-29 10:58:43 +04:00
* Copyright ( C ) 2006 - 2011 Hermann Kneissel herkne @ gmx . de
2005-04-17 02:20:36 +04:00
*
* The latest version of the driver can be found at
* http : //sourceforge.net/projects/garmin-gps/
*
* This driver has been derived from v2 .1 of the visor driver .
*/
# include <linux/kernel.h>
# include <linux/errno.h>
# include <linux/slab.h>
# include <linux/timer.h>
# include <linux/tty.h>
# include <linux/tty_driver.h>
# include <linux/tty_flip.h>
# include <linux/module.h>
# include <linux/spinlock.h>
2008-07-22 14:11:44 +04:00
# include <linux/uaccess.h>
2011-07-27 03:09:06 +04:00
# include <linux/atomic.h>
2005-04-17 02:20:36 +04:00
# include <linux/usb.h>
2006-07-12 08:22:58 +04:00
# include <linux/usb/serial.h>
2005-04-17 02:20:36 +04:00
/* the mode to be set when the port ist opened */
static int initial_mode = 1 ;
# define GARMIN_VENDOR_ID 0x091E
/*
* Version Information
*/
# define VERSION_MAJOR 0
2011-04-29 10:58:43 +04:00
# define VERSION_MINOR 36
2005-04-17 02:20:36 +04:00
# define _STR(s) #s
2008-07-22 14:11:44 +04:00
# define _DRIVER_VERSION(a, b) "v" _STR(a) "." _STR(b)
2005-04-17 02:20:36 +04:00
# define DRIVER_VERSION _DRIVER_VERSION(VERSION_MAJOR, VERSION_MINOR)
# define DRIVER_AUTHOR "hermann kneissel"
# define DRIVER_DESC "garmin gps driver"
/* error codes returned by the driver */
# define EINVPKT 1000 /* invalid packet structure */
2008-07-22 14:11:44 +04:00
/* size of the header of a packet using the usb protocol */
2005-04-17 02:20:36 +04:00
# define GARMIN_PKTHDR_LENGTH 12
2008-07-22 14:11:44 +04:00
/* max. possible size of a packet using the serial protocol */
# define MAX_SERIAL_PKT_SIZ (3 + 255 + 3)
2005-04-17 02:20:36 +04:00
2008-07-22 14:11:44 +04:00
/* max. possible size of a packet with worst case stuffing */
# define MAX_SERIAL_PKT_SIZ_STUFFED (MAX_SERIAL_PKT_SIZ + 256)
2005-04-17 02:20:36 +04:00
2008-07-22 14:11:44 +04:00
/* size of a buffer able to hold a complete (no stuffing) packet
* ( the document protocol does not contain packets with a larger
* size , but in theory a packet may be 64 k + 12 bytes - if in
* later protocol versions larger packet sizes occur , this value
* should be increased accordingly , so the input buffer is always
* large enough the store a complete packet inclusive header ) */
# define GPS_IN_BUFSIZ (GARMIN_PKTHDR_LENGTH+MAX_SERIAL_PKT_SIZ)
2005-04-17 02:20:36 +04:00
2008-07-22 14:11:44 +04:00
/* size of a buffer able to hold a complete (incl. stuffing) packet */
# define GPS_OUT_BUFSIZ (GARMIN_PKTHDR_LENGTH+MAX_SERIAL_PKT_SIZ_STUFFED)
2005-04-17 02:20:36 +04:00
2008-07-22 14:11:44 +04:00
/* where to place the packet id of a serial packet, so we can
* prepend the usb - packet header without the need to move the
* packets data */
2005-04-17 02:20:36 +04:00
# define GSP_INITIAL_OFFSET (GARMIN_PKTHDR_LENGTH-2)
2008-07-22 14:11:44 +04:00
/* max. size of incoming private packets (header+1 param) */
2005-04-17 02:20:36 +04:00
# define PRIVPKTSIZ (GARMIN_PKTHDR_LENGTH+4)
# define GARMIN_LAYERID_TRANSPORT 0
# define GARMIN_LAYERID_APPL 20
2008-07-22 14:11:44 +04:00
/* our own layer-id to use for some control mechanisms */
2005-04-17 02:20:36 +04:00
# define GARMIN_LAYERID_PRIVATE 0x01106E4B
# define GARMIN_PKTID_PVT_DATA 51
# define GARMIN_PKTID_L001_COMMAND_DATA 10
# define CMND_ABORT_TRANSFER 0
2008-07-22 14:11:44 +04:00
/* packet ids used in private layer */
2005-04-17 02:20:36 +04:00
# define PRIV_PKTID_SET_DEBUG 1
# define PRIV_PKTID_SET_MODE 2
# define PRIV_PKTID_INFO_REQ 3
# define PRIV_PKTID_INFO_RESP 4
# define PRIV_PKTID_RESET_REQ 5
# define PRIV_PKTID_SET_DEF_MODE 6
# define ETX 0x03
# define DLE 0x10
# define ACK 0x06
# define NAK 0x15
/* structure used to queue incoming packets */
struct garmin_packet {
struct list_head list ;
int seq ;
2008-07-22 14:11:44 +04:00
/* the real size of the data array, always > 0 */
int size ;
2005-04-17 02:20:36 +04:00
__u8 data [ 1 ] ;
} ;
/* structure used to keep the current state of the driver */
struct garmin_data {
__u8 state ;
__u16 flags ;
__u8 mode ;
__u8 count ;
__u8 pkt_id ;
__u32 serial_num ;
struct timer_list timer ;
struct usb_serial_port * port ;
int seq_counter ;
int insize ;
int outsize ;
__u8 inbuffer [ GPS_IN_BUFSIZ ] ; /* tty -> usb */
__u8 outbuffer [ GPS_OUT_BUFSIZ ] ; /* usb -> tty */
__u8 privpkt [ 4 * 6 ] ;
spinlock_t lock ;
struct list_head pktlist ;
2017-10-11 15:02:57 +03:00
struct usb_anchor write_urbs ;
2005-04-17 02:20:36 +04:00
} ;
# define STATE_NEW 0
# define STATE_INITIAL_DELAY 1
# define STATE_TIMEOUT 2
# define STATE_SESSION_REQ1 3
# define STATE_SESSION_REQ2 4
# define STATE_ACTIVE 5
# define STATE_RESET 8
# define STATE_DISCONNECTED 9
# define STATE_WAIT_TTY_ACK 10
# define STATE_GSP_WAIT_DATA 11
# define MODE_NATIVE 0
# define MODE_GARMIN_SERIAL 1
2008-07-22 14:11:44 +04:00
/* Flags used in garmin_data.flags: */
2005-04-17 02:20:36 +04:00
# define FLAGS_SESSION_REPLY_MASK 0x00C0
# define FLAGS_SESSION_REPLY1_SEEN 0x0080
# define FLAGS_SESSION_REPLY2_SEEN 0x0040
# define FLAGS_BULK_IN_ACTIVE 0x0020
2006-07-11 21:41:33 +04:00
# define FLAGS_BULK_IN_RESTART 0x0010
# define FLAGS_THROTTLED 0x0008
2009-04-27 00:42:04 +04:00
# define APP_REQ_SEEN 0x0004
# define APP_RESP_SEEN 0x0002
2005-04-17 02:20:36 +04:00
# define CLEAR_HALT_REQUIRED 0x0001
# define FLAGS_QUEUING 0x0100
# define FLAGS_DROP_DATA 0x0800
# define FLAGS_GSP_SKIP 0x1000
# define FLAGS_GSP_DLESEEN 0x2000
/* function prototypes */
2009-04-27 00:42:04 +04:00
static int gsp_next_packet ( struct garmin_data * garmin_data_p ) ;
static int garmin_write_bulk ( struct usb_serial_port * port ,
2007-08-03 22:20:33 +04:00
const unsigned char * buf , int count ,
int dismiss_ack ) ;
2005-04-17 02:20:36 +04:00
/* 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_REPLY [ ]
= { 0 , 0 , 0 , 0 , 6 , 0 , 0 , 0 , 4 , 0 , 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 [ ]
= { 0x14 , 0 , 0 , 0 } ;
static unsigned char const GARMIN_START_PVT_REQ [ ]
= { 20 , 0 , 0 , 0 , 10 , 0 , 0 , 0 , 2 , 0 , 0 , 0 , 49 , 0 } ;
static unsigned char const GARMIN_STOP_PVT_REQ [ ]
= { 20 , 0 , 0 , 0 , 10 , 0 , 0 , 0 , 2 , 0 , 0 , 0 , 50 , 0 } ;
static unsigned char const GARMIN_STOP_TRANSFER_REQ [ ]
= { 20 , 0 , 0 , 0 , 10 , 0 , 0 , 0 , 2 , 0 , 0 , 0 , 0 , 0 } ;
static unsigned char const GARMIN_STOP_TRANSFER_REQ_V2 [ ]
= { 20 , 0 , 0 , 0 , 10 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 } ;
static unsigned char const PRIVATE_REQ [ ]
= { 0x4B , 0x6E , 0x10 , 0x01 , 0xFF , 0 , 0 , 0 , 0xFF , 0 , 0 , 0 } ;
2010-01-10 17:34:24 +03:00
static const struct usb_device_id id_table [ ] = {
2008-07-22 14:11:44 +04:00
/* the same device id seems to be used by all
usb enabled GPS devices */
{ USB_DEVICE ( GARMIN_VENDOR_ID , 3 ) } ,
2005-04-17 02:20:36 +04:00
{ } /* Terminating entry */
} ;
2008-07-22 14:11:44 +04:00
MODULE_DEVICE_TABLE ( usb , id_table ) ;
2005-04-17 02:20:36 +04:00
static inline int getLayerId ( const __u8 * usbPacket )
{
return __le32_to_cpup ( ( __le32 * ) ( usbPacket ) ) ;
}
static inline int getPacketId ( const __u8 * usbPacket )
{
return __le32_to_cpup ( ( __le32 * ) ( usbPacket + 4 ) ) ;
}
static inline int getDataLength ( const __u8 * usbPacket )
{
return __le32_to_cpup ( ( __le32 * ) ( usbPacket + 8 ) ) ;
}
/*
* check if the usb - packet in buf contains an abort - transfer command .
* ( if yes , all queued data will be dropped )
*/
static inline int isAbortTrfCmnd ( const unsigned char * buf )
{
2016-02-04 21:01:27 +03:00
if ( memcmp ( buf , GARMIN_STOP_TRANSFER_REQ ,
sizeof ( GARMIN_STOP_TRANSFER_REQ ) ) = = 0 | |
memcmp ( buf , GARMIN_STOP_TRANSFER_REQ_V2 ,
sizeof ( GARMIN_STOP_TRANSFER_REQ_V2 ) ) = = 0 )
2005-04-17 02:20:36 +04:00
return 1 ;
else
return 0 ;
}
static void send_to_tty ( struct usb_serial_port * port ,
2006-07-11 21:41:33 +04:00
char * data , unsigned int actual_length )
2005-04-17 02:20:36 +04:00
{
2013-01-03 18:53:06 +04:00
if ( actual_length ) {
2012-09-18 12:58:57 +04:00
usb_serial_debug_data ( & port - > dev , __func__ , actual_length , data ) ;
2013-01-03 18:53:04 +04:00
tty_insert_flip_string ( & port - > port , data , actual_length ) ;
2013-01-03 18:53:06 +04:00
tty_flip_buffer_push ( & port - > port ) ;
2005-04-17 02:20:36 +04:00
}
}
/******************************************************************************
* packet queue handling
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
* queue a received ( usb - ) packet for later processing
*/
2008-07-22 14:11:44 +04:00
static int pkt_add ( struct garmin_data * garmin_data_p ,
2006-07-11 21:41:33 +04:00
unsigned char * data , unsigned int data_length )
2005-04-17 02:20:36 +04:00
{
2006-07-11 21:41:33 +04:00
int state = 0 ;
2005-04-17 02:20:36 +04:00
int result = 0 ;
unsigned long flags ;
struct garmin_packet * pkt ;
2014-01-02 17:59:24 +04:00
/* process only packets containing data ... */
2005-04-17 02:20:36 +04:00
if ( data_length ) {
pkt = kmalloc ( sizeof ( struct garmin_packet ) + data_length ,
2008-07-22 14:11:44 +04:00
GFP_ATOMIC ) ;
2013-12-29 22:22:56 +04:00
if ( ! pkt )
2005-04-17 02:20:36 +04:00
return 0 ;
2013-12-29 22:22:56 +04:00
2005-04-17 02:20:36 +04:00
pkt - > size = data_length ;
memcpy ( pkt - > data , data , data_length ) ;
spin_lock_irqsave ( & garmin_data_p - > lock , flags ) ;
2006-07-11 21:41:33 +04:00
garmin_data_p - > flags | = FLAGS_QUEUING ;
2005-04-17 02:20:36 +04:00
result = list_empty ( & garmin_data_p - > pktlist ) ;
pkt - > seq = garmin_data_p - > seq_counter + + ;
list_add_tail ( & pkt - > list , & garmin_data_p - > pktlist ) ;
2006-07-11 21:41:33 +04:00
state = garmin_data_p - > state ;
2005-04-17 02:20:36 +04:00
spin_unlock_irqrestore ( & garmin_data_p - > lock , flags ) ;
2012-09-14 22:50:30 +04:00
dev_dbg ( & garmin_data_p - > port - > dev ,
" %s - added: pkt: %d - %d bytes \n " , __func__ ,
pkt - > seq , data_length ) ;
2009-04-27 00:42:04 +04:00
2005-04-17 02:20:36 +04:00
/* in serial mode, if someone is waiting for data from
2009-04-27 00:42:04 +04:00
the device , convert and send the next packet to tty . */
2008-07-22 14:11:44 +04:00
if ( result & & ( state = = STATE_GSP_WAIT_DATA ) )
2005-04-17 02:20:36 +04:00
gsp_next_packet ( garmin_data_p ) ;
}
return result ;
}
/* get the next pending packet */
2008-07-22 14:11:44 +04:00
static struct garmin_packet * pkt_pop ( struct garmin_data * garmin_data_p )
2005-04-17 02:20:36 +04:00
{
unsigned long flags ;
struct garmin_packet * result = NULL ;
spin_lock_irqsave ( & garmin_data_p - > lock , flags ) ;
if ( ! list_empty ( & garmin_data_p - > pktlist ) ) {
result = ( struct garmin_packet * ) garmin_data_p - > pktlist . next ;
list_del ( & result - > list ) ;
}
spin_unlock_irqrestore ( & garmin_data_p - > lock , flags ) ;
return result ;
}
/* free up all queued data */
2008-07-22 14:11:44 +04:00
static void pkt_clear ( struct garmin_data * garmin_data_p )
2005-04-17 02:20:36 +04:00
{
unsigned long flags ;
struct garmin_packet * result = NULL ;
spin_lock_irqsave ( & garmin_data_p - > lock , flags ) ;
while ( ! list_empty ( & garmin_data_p - > pktlist ) ) {
result = ( struct garmin_packet * ) garmin_data_p - > pktlist . next ;
list_del ( & result - > list ) ;
kfree ( result ) ;
}
spin_unlock_irqrestore ( & garmin_data_p - > lock , flags ) ;
}
/******************************************************************************
* garmin serial protocol handling handling
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* send an ack packet back to the tty */
2008-07-22 14:11:44 +04:00
static int gsp_send_ack ( struct garmin_data * garmin_data_p , __u8 pkt_id )
2005-04-17 02:20:36 +04:00
{
__u8 pkt [ 10 ] ;
2006-07-11 21:41:33 +04:00
__u8 cksum = 0 ;
__u8 * ptr = pkt ;
unsigned l = 0 ;
2005-04-17 02:20:36 +04:00
2012-09-14 22:50:30 +04:00
dev_dbg ( & garmin_data_p - > port - > dev , " %s - pkt-id: 0x%X. \n " , __func__ ,
2016-02-04 21:01:27 +03:00
pkt_id ) ;
2005-04-17 02:20:36 +04:00
* ptr + + = DLE ;
* ptr + + = ACK ;
cksum + = ACK ;
* ptr + + = 2 ;
cksum + = 2 ;
* ptr + + = pkt_id ;
cksum + = pkt_id ;
2008-07-22 14:11:44 +04:00
if ( pkt_id = = DLE )
2005-04-17 02:20:36 +04:00
* ptr + + = DLE ;
* ptr + + = 0 ;
2016-02-04 21:01:27 +03:00
* ptr + + = ( - cksum ) & 0xFF ;
2005-04-17 02:20:36 +04:00
* ptr + + = DLE ;
* ptr + + = ETX ;
l = ptr - pkt ;
send_to_tty ( garmin_data_p - > port , pkt , l ) ;
return 0 ;
}
/*
* called for a complete packet received from tty layer
*
2009-04-27 00:42:04 +04:00
* the complete packet ( pktid . . . cksum ) is in garmin_data_p - > inbuf starting
2005-04-17 02:20:36 +04:00
* at GSP_INITIAL_OFFSET .
*
* count - number of bytes in the input buffer including space reserved for
2008-07-22 14:11:44 +04:00
* the usb header : GSP_INITIAL_OFFSET + number of bytes in packet
2005-04-17 02:20:36 +04:00
* ( including pkt - id , data - length a . cksum )
*/
2008-07-22 14:11:44 +04:00
static int gsp_rec_packet ( struct garmin_data * garmin_data_p , int count )
2005-04-17 02:20:36 +04:00
{
2012-09-14 22:50:30 +04:00
struct device * dev = & garmin_data_p - > port - > dev ;
2011-04-29 10:58:43 +04:00
unsigned long flags ;
2008-07-22 14:11:44 +04:00
const __u8 * recpkt = garmin_data_p - > inbuffer + GSP_INITIAL_OFFSET ;
2006-07-11 21:41:33 +04:00
__le32 * usbdata = ( __le32 * ) garmin_data_p - > inbuffer ;
2005-04-17 02:20:36 +04:00
int cksum = 0 ;
int n = 0 ;
int pktid = recpkt [ 0 ] ;
int size = recpkt [ 1 ] ;
2012-09-18 12:58:57 +04:00
usb_serial_debug_data ( & garmin_data_p - > port - > dev , __func__ ,
count - GSP_INITIAL_OFFSET , recpkt ) ;
2005-04-17 02:20:36 +04:00
if ( size ! = ( count - GSP_INITIAL_OFFSET - 3 ) ) {
2012-09-14 22:50:30 +04:00
dev_dbg ( dev , " %s - invalid size, expected %d bytes, got %d \n " ,
2008-03-04 03:08:34 +03:00
__func__ , size , ( count - GSP_INITIAL_OFFSET - 3 ) ) ;
2005-04-17 02:20:36 +04:00
return - EINVPKT ;
}
cksum + = * recpkt + + ;
cksum + = * recpkt + + ;
2008-07-22 14:11:44 +04:00
/* sanity check, remove after test ... */
if ( ( __u8 * ) & ( usbdata [ 3 ] ) ! = recpkt ) {
2012-09-14 22:50:30 +04:00
dev_dbg ( dev , " %s - ptr mismatch %p - %p \n " , __func__ ,
& ( usbdata [ 4 ] ) , recpkt ) ;
2005-04-17 02:20:36 +04:00
return - EINVPKT ;
}
while ( n < size ) {
cksum + = * recpkt + + ;
n + + ;
}
2016-02-04 21:01:27 +03:00
if ( ( ( cksum + * recpkt ) & 0xff ) ! = 0 ) {
2012-09-14 22:50:30 +04:00
dev_dbg ( dev , " %s - invalid checksum, expected %02x, got %02x \n " ,
2016-02-04 21:01:27 +03:00
__func__ , - cksum & 0xff , * recpkt ) ;
2006-07-11 21:41:33 +04:00
return - EINVPKT ;
}
2005-04-17 02:20:36 +04:00
usbdata [ 0 ] = __cpu_to_le32 ( GARMIN_LAYERID_APPL ) ;
usbdata [ 1 ] = __cpu_to_le32 ( pktid ) ;
usbdata [ 2 ] = __cpu_to_le32 ( size ) ;
2008-07-22 14:11:44 +04:00
garmin_write_bulk ( garmin_data_p - > port , garmin_data_p - > inbuffer ,
2007-08-03 22:20:33 +04:00
GARMIN_PKTHDR_LENGTH + size , 0 ) ;
2005-04-17 02:20:36 +04:00
/* if this was an abort-transfer command, flush all
queued data . */
if ( isAbortTrfCmnd ( garmin_data_p - > inbuffer ) ) {
2011-04-29 10:58:43 +04:00
spin_lock_irqsave ( & garmin_data_p - > lock , flags ) ;
2005-04-17 02:20:36 +04:00
garmin_data_p - > flags | = FLAGS_DROP_DATA ;
2011-04-29 10:58:43 +04:00
spin_unlock_irqrestore ( & garmin_data_p - > lock , flags ) ;
2005-04-17 02:20:36 +04:00
pkt_clear ( garmin_data_p ) ;
}
return count ;
}
/*
* Called for data received from tty
*
* buf contains the data read , it may span more than one packet or even
* incomplete packets
*
* input record should be a serial - record , but it may not be complete .
* Copy it into our local buffer , until an etx is seen ( or an error
* occurs ) .
* Once the record is complete , convert into a usb packet and send it
* to the bulk pipe , send an ack back to the tty .
*
* If the input is an ack , just send the last queued packet to the
* tty layer .
*
* if the input is an abort command , drop all queued data .
*/
2008-07-22 14:11:44 +04:00
static int gsp_receive ( struct garmin_data * garmin_data_p ,
2006-07-11 21:41:33 +04:00
const unsigned char * buf , int count )
2005-04-17 02:20:36 +04:00
{
2012-09-14 22:50:30 +04:00
struct device * dev = & garmin_data_p - > port - > dev ;
2006-07-11 21:41:33 +04:00
unsigned long flags ;
2005-04-17 02:20:36 +04:00
int offs = 0 ;
int ack_or_nak_seen = 0 ;
2006-07-11 21:41:33 +04:00
__u8 * dest ;
int size ;
2008-07-22 14:11:44 +04:00
/* dleSeen: set if last byte read was a DLE */
2006-07-11 21:41:33 +04:00
int dleSeen ;
2008-07-22 14:11:44 +04:00
/* skip: if set, skip incoming data until possible start of
* new packet
*/
2006-07-11 21:41:33 +04:00
int skip ;
2005-04-17 02:20:36 +04:00
__u8 data ;
2006-07-11 21:41:33 +04:00
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 ) ;
2012-09-14 22:50:30 +04:00
/* dev_dbg(dev, "%s - dle=%d skip=%d size=%d count=%d\n",
2009-04-27 00:42:04 +04:00
__func__ , dleSeen , skip , size , count ) ; */
2005-04-17 02:20:36 +04:00
2008-07-22 14:11:44 +04:00
if ( size = = 0 )
2005-04-17 02:20:36 +04:00
size = GSP_INITIAL_OFFSET ;
while ( offs < count ) {
data = * ( buf + offs ) ;
2008-07-22 14:11:44 +04:00
offs + + ;
2005-04-17 02:20:36 +04:00
if ( data = = DLE ) {
if ( skip ) { /* start of a new pkt */
skip = 0 ;
size = GSP_INITIAL_OFFSET ;
dleSeen = 1 ;
} else if ( dleSeen ) {
dest [ size + + ] = data ;
dleSeen = 0 ;
} else {
dleSeen = 1 ;
}
} else if ( data = = ETX ) {
if ( dleSeen ) {
/* packet complete */
data = dest [ GSP_INITIAL_OFFSET ] ;
if ( data = = ACK ) {
ack_or_nak_seen = ACK ;
2012-09-14 22:50:30 +04:00
dev_dbg ( dev , " ACK packet complete. \n " ) ;
2005-04-17 02:20:36 +04:00
} else if ( data = = NAK ) {
ack_or_nak_seen = NAK ;
2012-09-14 22:50:30 +04:00
dev_dbg ( dev , " NAK packet complete. \n " ) ;
2005-04-17 02:20:36 +04:00
} else {
2012-09-14 22:50:30 +04:00
dev_dbg ( dev , " packet complete - id=0x%X. \n " ,
2016-02-04 21:01:27 +03:00
data ) ;
2005-04-17 02:20:36 +04:00
gsp_rec_packet ( garmin_data_p , size ) ;
}
skip = 1 ;
size = GSP_INITIAL_OFFSET ;
dleSeen = 0 ;
} else {
dest [ size + + ] = data ;
}
} else if ( ! skip ) {
if ( dleSeen ) {
size = GSP_INITIAL_OFFSET ;
dleSeen = 0 ;
}
dest [ size + + ] = data ;
}
if ( size > = GPS_IN_BUFSIZ ) {
2012-09-14 22:50:30 +04:00
dev_dbg ( dev , " %s - packet too large. \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
skip = 1 ;
size = GSP_INITIAL_OFFSET ;
dleSeen = 0 ;
}
}
2006-07-11 21:41:33 +04:00
spin_lock_irqsave ( & garmin_data_p - > lock , flags ) ;
2005-04-17 02:20:36 +04:00
garmin_data_p - > insize = size ;
2008-07-22 14:11:44 +04:00
/* copy flags back to structure */
2005-04-17 02:20:36 +04:00
if ( skip )
garmin_data_p - > flags | = FLAGS_GSP_SKIP ;
else
garmin_data_p - > flags & = ~ FLAGS_GSP_SKIP ;
if ( dleSeen )
garmin_data_p - > flags | = FLAGS_GSP_DLESEEN ;
else
garmin_data_p - > flags & = ~ FLAGS_GSP_DLESEEN ;
2006-07-11 21:41:33 +04:00
spin_unlock_irqrestore ( & garmin_data_p - > lock , flags ) ;
2009-04-27 00:42:04 +04:00
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 ;
}
2005-04-17 02:20:36 +04:00
return count ;
}
/*
* Sends a usb packet to the tty
*
* Assumes , that all packages and at an usb - packet boundary .
*
* return < 0 on error , 0 if packet is incomplete or > 0 if packet was sent
*/
2008-07-22 14:11:44 +04:00
static int gsp_send ( struct garmin_data * garmin_data_p ,
2005-04-17 02:20:36 +04:00
const unsigned char * buf , int count )
{
2012-09-14 22:50:30 +04:00
struct device * dev = & garmin_data_p - > port - > dev ;
2005-04-17 02:20:36 +04:00
const unsigned char * src ;
unsigned char * dst ;
int pktid = 0 ;
int datalen = 0 ;
int cksum = 0 ;
2008-07-22 14:11:44 +04:00
int i = 0 ;
2005-04-17 02:20:36 +04:00
int k ;
2012-09-14 22:50:30 +04:00
dev_dbg ( dev , " %s - state %d - %d bytes. \n " , __func__ ,
garmin_data_p - > state , count ) ;
2005-04-17 02:20:36 +04:00
k = garmin_data_p - > outsize ;
if ( ( k + count ) > GPS_OUT_BUFSIZ ) {
2012-09-14 22:50:30 +04:00
dev_dbg ( dev , " packet too large \n " ) ;
2005-04-17 02:20:36 +04:00
garmin_data_p - > outsize = 0 ;
return - 4 ;
}
memcpy ( garmin_data_p - > outbuffer + k , buf , count ) ;
k + = count ;
garmin_data_p - > outsize = k ;
if ( k > = GARMIN_PKTHDR_LENGTH ) {
pktid = getPacketId ( garmin_data_p - > outbuffer ) ;
2008-07-22 14:11:44 +04:00
datalen = getDataLength ( garmin_data_p - > outbuffer ) ;
2005-04-17 02:20:36 +04:00
i = GARMIN_PKTHDR_LENGTH + datalen ;
if ( k < i )
return 0 ;
} else {
return 0 ;
}
2012-09-14 22:50:30 +04:00
dev_dbg ( dev , " %s - %d bytes in buffer, %d bytes in pkt. \n " , __func__ , k , i ) ;
2005-04-17 02:20:36 +04:00
/* garmin_data_p->outbuffer now contains a complete packet */
2012-09-18 12:58:57 +04:00
usb_serial_debug_data ( & garmin_data_p - > port - > dev , __func__ , k ,
garmin_data_p - > outbuffer ) ;
2005-04-17 02:20:36 +04:00
garmin_data_p - > outsize = 0 ;
2016-02-04 21:01:27 +03:00
if ( getLayerId ( garmin_data_p - > outbuffer ) ! = GARMIN_LAYERID_APPL ) {
2012-09-14 22:50:30 +04:00
dev_dbg ( dev , " not an application packet (%d) \n " ,
2008-07-22 14:11:44 +04:00
getLayerId ( garmin_data_p - > outbuffer ) ) ;
2005-04-17 02:20:36 +04:00
return - 1 ;
}
if ( pktid > 255 ) {
2012-09-14 22:50:30 +04:00
dev_dbg ( dev , " packet-id %d too large \n " , pktid ) ;
2005-04-17 02:20:36 +04:00
return - 2 ;
}
if ( datalen > 255 ) {
2012-09-14 22:50:30 +04:00
dev_dbg ( dev , " packet-size %d too large \n " , datalen ) ;
2005-04-17 02:20:36 +04:00
return - 3 ;
}
/* the serial protocol should be able to handle this packet */
k = 0 ;
src = garmin_data_p - > outbuffer + GARMIN_PKTHDR_LENGTH ;
2008-07-22 14:11:44 +04:00
for ( i = 0 ; i < datalen ; i + + ) {
2005-04-17 02:20:36 +04:00
if ( * src + + = = DLE )
k + + ;
}
src = garmin_data_p - > outbuffer + GARMIN_PKTHDR_LENGTH ;
if ( k > ( GARMIN_PKTHDR_LENGTH - 2 ) ) {
2008-07-22 14:11:44 +04:00
/* can't add stuffing DLEs in place, move data to end
2006-07-11 21:41:33 +04:00
of buffer . . . */
2005-04-17 02:20:36 +04:00
dst = garmin_data_p - > outbuffer + GPS_OUT_BUFSIZ - datalen ;
memcpy ( dst , src , datalen ) ;
src = dst ;
}
dst = garmin_data_p - > outbuffer ;
* dst + + = DLE ;
* dst + + = pktid ;
cksum + = pktid ;
* dst + + = datalen ;
cksum + = datalen ;
if ( datalen = = DLE )
* dst + + = DLE ;
2008-07-22 14:11:44 +04:00
for ( i = 0 ; i < datalen ; i + + ) {
2005-04-17 02:20:36 +04:00
__u8 c = * src + + ;
* dst + + = c ;
cksum + = c ;
if ( c = = DLE )
* dst + + = DLE ;
}
2008-07-22 14:11:44 +04:00
2016-02-04 21:01:27 +03:00
cksum = - cksum & 0xFF ;
2005-04-17 02:20:36 +04:00
* dst + + = cksum ;
if ( cksum = = DLE )
* dst + + = DLE ;
* dst + + = DLE ;
* dst + + = ETX ;
i = dst - garmin_data_p - > outbuffer ;
send_to_tty ( garmin_data_p - > port , garmin_data_p - > outbuffer , i ) ;
garmin_data_p - > pkt_id = pktid ;
garmin_data_p - > state = STATE_WAIT_TTY_ACK ;
return i ;
}
/*
* Process the next pending data packet - if there is one
*/
2009-04-27 00:42:04 +04:00
static int gsp_next_packet ( struct garmin_data * garmin_data_p )
2005-04-17 02:20:36 +04:00
{
2009-04-27 00:42:04 +04:00
int result = 0 ;
2005-04-17 02:20:36 +04:00
struct garmin_packet * pkt = NULL ;
while ( ( pkt = pkt_pop ( garmin_data_p ) ) ! = NULL ) {
2012-09-14 22:50:30 +04:00
dev_dbg ( & garmin_data_p - > port - > dev , " %s - next pkt: %d \n " , __func__ , pkt - > seq ) ;
2009-04-27 00:42:04 +04:00
result = gsp_send ( garmin_data_p , pkt - > data , pkt - > size ) ;
if ( result > 0 ) {
2005-04-17 02:20:36 +04:00
kfree ( pkt ) ;
2009-04-27 00:42:04 +04:00
return result ;
2005-04-17 02:20:36 +04:00
}
kfree ( pkt ) ;
}
2009-04-27 00:42:04 +04:00
return result ;
2005-04-17 02:20:36 +04:00
}
/******************************************************************************
* garmin native mode
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
* Called for data received from tty
*
* The input data is expected to be in garmin usb - packet format .
*
* buf contains the data read , it may span more than one packet
* or even incomplete packets
*/
2008-07-22 14:11:44 +04:00
static int nat_receive ( struct garmin_data * garmin_data_p ,
2006-07-11 21:41:33 +04:00
const unsigned char * buf , int count )
2005-04-17 02:20:36 +04:00
{
2006-07-11 21:41:33 +04:00
unsigned long flags ;
2008-07-22 14:11:44 +04:00
__u8 * dest ;
2005-04-17 02:20:36 +04:00
int offs = 0 ;
int result = count ;
int len ;
while ( offs < count ) {
2008-07-22 14:11:44 +04:00
/* if buffer contains header, copy rest of data */
2005-04-17 02:20:36 +04:00
if ( garmin_data_p - > insize > = GARMIN_PKTHDR_LENGTH )
len = GARMIN_PKTHDR_LENGTH
+ getDataLength ( garmin_data_p - > inbuffer ) ;
else
len = GARMIN_PKTHDR_LENGTH ;
if ( len > = GPS_IN_BUFSIZ ) {
2008-07-22 14:11:44 +04:00
/* seems to be an invalid packet, ignore rest
of input */
2012-09-14 22:50:30 +04:00
dev_dbg ( & garmin_data_p - > port - > dev ,
" %s - packet size too large: %d \n " ,
__func__ , len ) ;
2005-04-17 02:20:36 +04:00
garmin_data_p - > insize = 0 ;
count = 0 ;
result = - EINVPKT ;
} else {
len - = garmin_data_p - > insize ;
if ( len > ( count - offs ) )
len = ( count - offs ) ;
if ( len > 0 ) {
dest = garmin_data_p - > inbuffer
2008-07-22 14:11:44 +04:00
+ garmin_data_p - > insize ;
2005-04-17 02:20:36 +04:00
memcpy ( dest , buf + offs , len ) ;
garmin_data_p - > insize + = len ;
offs + = len ;
}
}
/* do we have a complete packet ? */
if ( garmin_data_p - > insize > = GARMIN_PKTHDR_LENGTH ) {
len = GARMIN_PKTHDR_LENGTH +
getDataLength ( garmin_data_p - > inbuffer ) ;
if ( garmin_data_p - > insize > = len ) {
2008-07-22 14:11:44 +04:00
garmin_write_bulk ( garmin_data_p - > port ,
garmin_data_p - > inbuffer ,
len , 0 ) ;
2005-04-17 02:20:36 +04:00
garmin_data_p - > insize = 0 ;
/* if this was an abort-transfer command,
flush all queued data . */
if ( isAbortTrfCmnd ( garmin_data_p - > inbuffer ) ) {
2008-07-22 14:11:44 +04:00
spin_lock_irqsave ( & garmin_data_p - > lock ,
flags ) ;
2005-04-17 02:20:36 +04:00
garmin_data_p - > flags | = FLAGS_DROP_DATA ;
2008-07-22 14:11:44 +04:00
spin_unlock_irqrestore (
& garmin_data_p - > lock , flags ) ;
2005-04-17 02:20:36 +04:00
pkt_clear ( garmin_data_p ) ;
}
}
}
}
return result ;
}
/******************************************************************************
* private packets
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void priv_status_resp ( struct usb_serial_port * port )
{
2008-07-22 14:11:44 +04:00
struct garmin_data * garmin_data_p = usb_get_serial_port_data ( port ) ;
2005-04-17 02:20:36 +04:00
__le32 * pkt = ( __le32 * ) garmin_data_p - > privpkt ;
pkt [ 0 ] = __cpu_to_le32 ( GARMIN_LAYERID_PRIVATE ) ;
pkt [ 1 ] = __cpu_to_le32 ( PRIV_PKTID_INFO_RESP ) ;
pkt [ 2 ] = __cpu_to_le32 ( 12 ) ;
pkt [ 3 ] = __cpu_to_le32 ( VERSION_MAJOR < < 16 | VERSION_MINOR ) ;
pkt [ 4 ] = __cpu_to_le32 ( garmin_data_p - > mode ) ;
pkt [ 5 ] = __cpu_to_le32 ( garmin_data_p - > serial_num ) ;
2008-07-22 14:11:44 +04:00
send_to_tty ( port , ( __u8 * ) pkt , 6 * 4 ) ;
2005-04-17 02:20:36 +04:00
}
/******************************************************************************
* Garmin specific driver functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int process_resetdev_request ( struct usb_serial_port * port )
{
2006-07-11 21:41:33 +04:00
unsigned long flags ;
2005-04-17 02:20:36 +04:00
int status ;
2008-07-22 14:11:44 +04:00
struct garmin_data * garmin_data_p = usb_get_serial_port_data ( port ) ;
2005-04-17 02:20:36 +04:00
2006-07-11 21:41:33 +04:00
spin_lock_irqsave ( & garmin_data_p - > lock , flags ) ;
2005-04-17 02:20:36 +04:00
garmin_data_p - > flags & = ~ ( CLEAR_HALT_REQUIRED ) ;
garmin_data_p - > state = STATE_RESET ;
garmin_data_p - > serial_num = 0 ;
2006-07-11 21:41:33 +04:00
spin_unlock_irqrestore ( & garmin_data_p - > lock , flags ) ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:11:44 +04:00
usb_kill_urb ( port - > interrupt_in_urb ) ;
2012-09-14 22:50:30 +04:00
dev_dbg ( & port - > dev , " %s - usb_reset_device \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
status = usb_reset_device ( port - > serial - > dev ) ;
if ( status )
2012-09-14 22:50:30 +04:00
dev_dbg ( & port - > dev , " %s - usb_reset_device failed: %d \n " ,
2008-03-04 03:08:34 +03:00
__func__ , status ) ;
2005-04-17 02:20:36 +04:00
return status ;
}
/*
* clear all cached data
*/
2008-07-22 14:11:44 +04:00
static int garmin_clear ( struct garmin_data * garmin_data_p )
2005-04-17 02:20:36 +04:00
{
2006-07-11 21:41:33 +04:00
unsigned long flags ;
2005-04-17 02:20:36 +04:00
/* flush all queued data */
pkt_clear ( garmin_data_p ) ;
2006-07-11 21:41:33 +04:00
spin_lock_irqsave ( & garmin_data_p - > lock , flags ) ;
2005-04-17 02:20:36 +04:00
garmin_data_p - > insize = 0 ;
garmin_data_p - > outsize = 0 ;
2006-07-11 21:41:33 +04:00
spin_unlock_irqrestore ( & garmin_data_p - > lock , flags ) ;
2005-04-17 02:20:36 +04:00
2016-02-04 21:01:28 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
static int garmin_init_session ( struct usb_serial_port * port )
{
2008-07-22 14:11:44 +04:00
struct garmin_data * garmin_data_p = usb_get_serial_port_data ( port ) ;
2017-10-11 15:03:01 +03:00
int status ;
int i ;
2005-04-17 02:20:36 +04:00
2017-10-11 15:03:01 +03:00
usb_kill_urb ( port - > interrupt_in_urb ) ;
2005-04-17 02:20:36 +04:00
2017-10-11 15:03:01 +03:00
status = usb_submit_urb ( port - > interrupt_in_urb , GFP_KERNEL ) ;
if ( status ) {
dev_err ( & port - > dev , " failed to submit interrupt urb: %d \n " ,
status ) ;
return status ;
2005-04-17 02:20:36 +04:00
}
2009-04-27 00:42:04 +04:00
/*
* using the initialization method from gpsbabel . See comments in
* gpsbabel / jeeps / gpslibusb . c gusb_reset_toggles ( )
*/
2017-10-11 15:03:01 +03:00
dev_dbg ( & port - > dev , " %s - starting session ... \n " , __func__ ) ;
garmin_data_p - > state = STATE_ACTIVE ;
2009-04-27 00:42:04 +04:00
2017-10-11 15:03:01 +03:00
for ( i = 0 ; i < 3 ; i + + ) {
status = garmin_write_bulk ( port , GARMIN_START_SESSION_REQ ,
sizeof ( GARMIN_START_SESSION_REQ ) , 0 ) ;
if ( status < 0 )
goto err_kill_urbs ;
2005-04-17 02:20:36 +04:00
}
2017-10-11 15:03:01 +03:00
return 0 ;
2017-10-11 15:02:57 +03:00
err_kill_urbs :
usb_kill_anchored_urbs ( & garmin_data_p - > write_urbs ) ;
usb_kill_urb ( port - > interrupt_in_urb ) ;
2005-04-17 02:20:36 +04:00
return status ;
}
2009-09-20 00:13:26 +04:00
static int garmin_open ( struct tty_struct * tty , struct usb_serial_port * port )
2005-04-17 02:20:36 +04:00
{
2006-07-11 21:41:33 +04:00
unsigned long flags ;
2005-04-17 02:20:36 +04:00
int status = 0 ;
2008-07-22 14:11:44 +04:00
struct garmin_data * garmin_data_p = usb_get_serial_port_data ( port ) ;
2005-04-17 02:20:36 +04:00
2006-07-11 21:41:33 +04:00
spin_lock_irqsave ( & garmin_data_p - > lock , flags ) ;
2005-04-17 02:20:36 +04:00
garmin_data_p - > mode = initial_mode ;
garmin_data_p - > count = 0 ;
2011-04-29 10:58:43 +04:00
garmin_data_p - > flags & = FLAGS_SESSION_REPLY1_SEEN ;
2006-07-11 21:41:33 +04:00
spin_unlock_irqrestore ( & garmin_data_p - > lock , flags ) ;
2005-04-17 02:20:36 +04:00
/* shutdown any bulk reads that might be going on */
2008-07-22 14:11:44 +04:00
usb_kill_urb ( port - > read_urb ) ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:09:07 +04:00
if ( garmin_data_p - > state = = STATE_RESET )
2005-04-17 02:20:36 +04:00
status = garmin_init_session ( port ) ;
garmin_data_p - > state = STATE_ACTIVE ;
return status ;
}
2009-06-11 15:26:29 +04:00
static void garmin_close ( struct usb_serial_port * port )
2005-04-17 02:20:36 +04:00
{
2008-07-22 14:11:44 +04:00
struct garmin_data * garmin_data_p = usb_get_serial_port_data ( port ) ;
2005-04-17 02:20:36 +04:00
2013-06-06 21:32:00 +04:00
dev_dbg ( & port - > dev , " %s - mode=%d state=%d flags=0x%X \n " ,
__func__ , garmin_data_p - > mode , garmin_data_p - > state ,
garmin_data_p - > flags ) ;
2005-04-17 02:20:36 +04:00
2013-03-19 12:21:07 +04:00
garmin_clear ( garmin_data_p ) ;
2005-04-17 02:20:36 +04:00
/* shutdown our urbs */
2008-07-22 14:11:44 +04:00
usb_kill_urb ( port - > read_urb ) ;
2017-10-11 15:02:57 +03:00
usb_kill_anchored_urbs ( & garmin_data_p - > write_urbs ) ;
2005-04-17 02:20:36 +04:00
2009-04-27 00:42:04 +04:00
/* keep reset state so we know that we must start a new session */
if ( garmin_data_p - > state ! = STATE_RESET )
2005-04-17 02:20:36 +04:00
garmin_data_p - > state = STATE_DISCONNECTED ;
}
2009-04-27 00:42:04 +04:00
2008-07-22 14:11:44 +04:00
static void garmin_write_bulk_callback ( struct urb * urb )
2005-04-17 02:20:36 +04:00
{
2008-02-24 13:41:47 +03:00
struct usb_serial_port * port = urb - > context ;
2005-04-17 02:20:36 +04:00
2007-08-03 22:20:33 +04:00
if ( port ) {
2008-07-22 14:11:44 +04:00
struct garmin_data * garmin_data_p =
usb_get_serial_port_data ( port ) ;
2005-04-17 02:20:36 +04:00
2016-02-04 21:01:27 +03:00
if ( getLayerId ( urb - > transfer_buffer ) = = GARMIN_LAYERID_APPL ) {
2007-08-03 22:20:33 +04:00
2009-04-27 00:42:04 +04:00
if ( garmin_data_p - > mode = = MODE_GARMIN_SERIAL ) {
gsp_send_ack ( garmin_data_p ,
( ( __u8 * ) urb - > transfer_buffer ) [ 4 ] ) ;
}
2007-08-03 22:20:33 +04:00
}
usb_serial_port_softint ( port ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-22 14:11:44 +04:00
/* Ignore errors that resulted from garmin_write_bulk with
dismiss_ack = 1 */
2007-08-03 22:20:33 +04:00
/* free up the transfer buffer, as usb_free_urb() does not do this */
2008-07-22 14:11:44 +04:00
kfree ( urb - > transfer_buffer ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-22 14:11:44 +04:00
static int garmin_write_bulk ( struct usb_serial_port * port ,
2007-08-03 22:20:33 +04:00
const unsigned char * buf , int count ,
int dismiss_ack )
2005-04-17 02:20:36 +04:00
{
2006-07-11 21:41:33 +04:00
unsigned long flags ;
2005-04-17 02:20:36 +04:00
struct usb_serial * serial = port - > serial ;
2008-07-22 14:11:44 +04:00
struct garmin_data * garmin_data_p = usb_get_serial_port_data ( port ) ;
2005-04-17 02:20:36 +04:00
struct urb * urb ;
unsigned char * buffer ;
int status ;
2006-07-11 21:41:33 +04:00
spin_lock_irqsave ( & garmin_data_p - > lock , flags ) ;
2005-04-17 02:20:36 +04:00
garmin_data_p - > flags & = ~ FLAGS_DROP_DATA ;
2006-07-11 21:41:33 +04:00
spin_unlock_irqrestore ( & garmin_data_p - > lock , flags ) ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:11:44 +04:00
buffer = kmalloc ( count , GFP_ATOMIC ) ;
2013-12-29 22:22:56 +04:00
if ( ! buffer )
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
urb = usb_alloc_urb ( 0 , GFP_ATOMIC ) ;
if ( ! urb ) {
2008-07-22 14:11:44 +04:00
kfree ( buffer ) ;
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
}
2008-07-22 14:11:44 +04:00
memcpy ( buffer , buf , count ) ;
2005-04-17 02:20:36 +04:00
2012-09-18 12:58:57 +04:00
usb_serial_debug_data ( & port - > dev , __func__ , count , buffer ) ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:11:44 +04:00
usb_fill_bulk_urb ( urb , serial - > dev ,
usb_sndbulkpipe ( serial - > dev ,
port - > bulk_out_endpointAddress ) ,
2005-04-17 02:20:36 +04:00
buffer , count ,
2007-08-03 22:20:33 +04:00
garmin_write_bulk_callback ,
dismiss_ack ? NULL : port ) ;
2005-04-17 02:20:36 +04:00
urb - > transfer_flags | = URB_ZERO_PACKET ;
2016-02-04 21:01:27 +03:00
if ( getLayerId ( buffer ) = = GARMIN_LAYERID_APPL ) {
2009-04-27 00:42:04 +04:00
spin_lock_irqsave ( & garmin_data_p - > lock , flags ) ;
garmin_data_p - > flags | = APP_REQ_SEEN ;
spin_unlock_irqrestore ( & garmin_data_p - > lock , flags ) ;
2005-04-17 02:20:36 +04:00
if ( garmin_data_p - > mode = = MODE_GARMIN_SERIAL ) {
pkt_clear ( garmin_data_p ) ;
garmin_data_p - > state = STATE_GSP_WAIT_DATA ;
}
}
/* send it down the pipe */
2017-10-11 15:02:57 +03:00
usb_anchor_urb ( urb , & garmin_data_p - > write_urbs ) ;
2005-04-17 02:20:36 +04:00
status = usb_submit_urb ( urb , GFP_ATOMIC ) ;
if ( status ) {
dev_err ( & port - > dev ,
2008-07-22 14:11:44 +04:00
" %s - usb_submit_urb(write bulk) failed with status = %d \n " ,
2008-03-04 03:08:34 +03:00
__func__ , status ) ;
2005-04-17 02:20:36 +04:00
count = status ;
2017-10-11 15:02:57 +03:00
usb_unanchor_urb ( urb ) ;
2017-01-03 18:39:41 +03:00
kfree ( buffer ) ;
2005-04-17 02:20:36 +04:00
}
/* we are done with this urb, so let the host driver
* really free it when it is finished with it */
2008-07-22 14:11:44 +04:00
usb_free_urb ( urb ) ;
2005-04-17 02:20:36 +04:00
return count ;
}
2008-07-22 14:11:44 +04:00
static int garmin_write ( struct tty_struct * tty , struct usb_serial_port * port ,
2008-07-22 14:09:07 +04:00
const unsigned char * buf , int count )
2005-04-17 02:20:36 +04:00
{
2012-09-14 22:50:30 +04:00
struct device * dev = & port - > dev ;
2005-04-17 02:20:36 +04:00
int pktid , pktsiz , len ;
2008-07-22 14:11:44 +04:00
struct garmin_data * garmin_data_p = usb_get_serial_port_data ( port ) ;
2005-04-17 02:20:36 +04:00
__le32 * privpkt = ( __le32 * ) garmin_data_p - > privpkt ;
2012-09-18 12:58:57 +04:00
usb_serial_debug_data ( dev , __func__ , count , buf ) ;
2005-04-17 02:20:36 +04:00
2009-04-27 00:42:04 +04:00
if ( garmin_data_p - > state = = STATE_RESET )
return - EIO ;
2005-04-17 02:20:36 +04:00
/* check for our private packets */
if ( count > = GARMIN_PKTHDR_LENGTH ) {
len = PRIVPKTSIZ ;
if ( count < len )
len = count ;
memcpy ( garmin_data_p - > privpkt , buf , len ) ;
pktsiz = getDataLength ( garmin_data_p - > privpkt ) ;
pktid = getPacketId ( garmin_data_p - > privpkt ) ;
2016-02-04 21:01:27 +03:00
if ( count = = ( GARMIN_PKTHDR_LENGTH + pktsiz ) & &
getLayerId ( garmin_data_p - > privpkt ) = =
GARMIN_LAYERID_PRIVATE ) {
2005-04-17 02:20:36 +04:00
2012-09-14 22:50:30 +04:00
dev_dbg ( dev , " %s - processing private request %d \n " ,
2008-03-04 03:08:34 +03:00
__func__ , pktid ) ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:11:44 +04:00
/* drop all unfinished transfers */
2005-04-17 02:20:36 +04:00
garmin_clear ( garmin_data_p ) ;
2008-07-22 14:11:44 +04:00
switch ( pktid ) {
2005-04-17 02:20:36 +04:00
case PRIV_PKTID_SET_MODE :
if ( pktsiz ! = 4 )
return - EINVPKT ;
garmin_data_p - > mode = __le32_to_cpu ( privpkt [ 3 ] ) ;
2012-09-14 22:50:30 +04:00
dev_dbg ( dev , " %s - mode set to %d \n " ,
2008-03-04 03:08:34 +03:00
__func__ , garmin_data_p - > mode ) ;
2005-04-17 02:20:36 +04:00
break ;
case PRIV_PKTID_INFO_REQ :
priv_status_resp ( port ) ;
break ;
case PRIV_PKTID_RESET_REQ :
2009-04-27 00:42:04 +04:00
process_resetdev_request ( port ) ;
2005-04-17 02:20:36 +04:00
break ;
case PRIV_PKTID_SET_DEF_MODE :
if ( pktsiz ! = 4 )
return - EINVPKT ;
initial_mode = __le32_to_cpu ( privpkt [ 3 ] ) ;
2012-09-14 22:50:30 +04:00
dev_dbg ( dev , " %s - initial_mode set to %d \n " ,
2008-03-04 03:08:34 +03:00
__func__ ,
2005-04-17 02:20:36 +04:00
garmin_data_p - > mode ) ;
break ;
}
return count ;
}
}
if ( garmin_data_p - > mode = = MODE_GARMIN_SERIAL ) {
return gsp_receive ( garmin_data_p , buf , count ) ;
} else { /* MODE_NATIVE */
return nat_receive ( garmin_data_p , buf , count ) ;
}
}
2008-07-22 14:09:07 +04:00
static int garmin_write_room ( struct tty_struct * tty )
2005-04-17 02:20:36 +04:00
{
2008-07-22 14:09:07 +04:00
struct usb_serial_port * port = tty - > driver_data ;
2005-04-17 02:20:36 +04:00
/*
* Report back the bytes currently available in the output buffer .
*/
2008-07-22 14:11:44 +04:00
struct garmin_data * garmin_data_p = usb_get_serial_port_data ( port ) ;
2005-04-17 02:20:36 +04:00
return GPS_OUT_BUFSIZ - garmin_data_p - > outsize ;
}
2008-07-22 14:11:44 +04:00
static void garmin_read_process ( struct garmin_data * garmin_data_p ,
2011-04-29 10:58:43 +04:00
unsigned char * data , unsigned data_length ,
int bulk_data )
2005-04-17 02:20:36 +04:00
{
2009-04-27 00:42:04 +04:00
unsigned long flags ;
2005-04-17 02:20:36 +04:00
if ( garmin_data_p - > flags & FLAGS_DROP_DATA ) {
2014-01-02 17:59:24 +04:00
/* abort-transfer cmd is active */
2012-09-14 22:50:30 +04:00
dev_dbg ( & garmin_data_p - > port - > dev , " %s - pkt dropped \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
} else if ( garmin_data_p - > state ! = STATE_DISCONNECTED & &
2008-07-22 14:11:44 +04:00
garmin_data_p - > state ! = STATE_RESET ) {
2005-04-17 02:20:36 +04:00
/* if throttling is active or postprecessing is required
2006-07-11 21:41:33 +04:00
put the received data in the input queue , otherwise
2005-04-17 02:20:36 +04:00
send it directly to the tty port */
if ( garmin_data_p - > flags & FLAGS_QUEUING ) {
pkt_add ( garmin_data_p , data , data_length ) ;
2012-09-14 22:50:30 +04:00
} else if ( bulk_data | |
2011-04-29 10:58:43 +04:00
getLayerId ( data ) = = GARMIN_LAYERID_APPL ) {
2009-04-27 00:42:04 +04:00
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 ) {
2005-04-17 02:20:36 +04:00
pkt_add ( garmin_data_p , data , data_length ) ;
2009-04-27 00:42:04 +04:00
} else {
send_to_tty ( garmin_data_p - > port , data ,
data_length ) ;
}
2005-04-17 02:20:36 +04:00
}
2009-04-27 00:42:04 +04:00
/* ignore system layer packets ... */
2005-04-17 02:20:36 +04:00
}
}
2008-07-22 14:11:44 +04:00
static void garmin_read_bulk_callback ( struct urb * urb )
2005-04-17 02:20:36 +04:00
{
2006-07-11 21:41:33 +04:00
unsigned long flags ;
2008-02-24 13:41:47 +03:00
struct usb_serial_port * port = urb - > context ;
2008-07-22 14:11:44 +04:00
struct garmin_data * garmin_data_p = usb_get_serial_port_data ( port ) ;
2005-04-17 02:20:36 +04:00
unsigned char * data = urb - > transfer_buffer ;
2007-06-16 02:44:13 +04:00
int status = urb - > status ;
int retval ;
2005-04-17 02:20:36 +04:00
2007-06-16 02:44:13 +04:00
if ( status ) {
2012-09-14 22:50:30 +04:00
dev_dbg ( & urb - > dev - > dev , " %s - nonzero read bulk status received: %d \n " ,
2008-03-04 03:08:34 +03:00
__func__ , status ) ;
2005-04-17 02:20:36 +04:00
return ;
}
2012-09-18 12:58:57 +04:00
usb_serial_debug_data ( & port - > dev , __func__ , urb - > actual_length , data ) ;
2005-04-17 02:20:36 +04:00
2011-04-29 10:58:43 +04:00
garmin_read_process ( garmin_data_p , data , urb - > actual_length , 1 ) ;
2005-04-17 02:20:36 +04:00
2006-07-11 21:41:33 +04:00
if ( urb - > actual_length = = 0 & &
2016-02-04 21:01:27 +03:00
( garmin_data_p - > flags & FLAGS_BULK_IN_RESTART ) ! = 0 ) {
2006-07-11 21:41:33 +04:00
spin_lock_irqsave ( & garmin_data_p - > lock , flags ) ;
garmin_data_p - > flags & = ~ FLAGS_BULK_IN_RESTART ;
spin_unlock_irqrestore ( & garmin_data_p - > lock , flags ) ;
2007-06-16 02:44:13 +04:00
retval = usb_submit_urb ( port - > read_urb , GFP_ATOMIC ) ;
if ( retval )
2005-04-17 02:20:36 +04:00
dev_err ( & port - > dev ,
" %s - failed resubmitting read urb, error %d \n " ,
2008-03-04 03:08:34 +03:00
__func__ , retval ) ;
2006-07-11 21:41:33 +04:00
} else if ( urb - > actual_length > 0 ) {
/* Continue trying to read until nothing more is received */
2016-02-04 21:01:27 +03:00
if ( ( garmin_data_p - > flags & FLAGS_THROTTLED ) = = 0 ) {
2007-06-16 02:44:13 +04:00
retval = usb_submit_urb ( port - > read_urb , GFP_ATOMIC ) ;
if ( retval )
2006-07-11 21:41:33 +04:00
dev_err ( & port - > dev ,
2012-09-14 22:50:30 +04:00
" %s - failed resubmitting read urb, error %d \n " ,
__func__ , retval ) ;
2006-07-11 21:41:33 +04:00
}
} else {
2012-09-14 22:50:30 +04:00
dev_dbg ( & port - > dev , " %s - end of bulk data \n " , __func__ ) ;
2006-07-11 21:41:33 +04:00
spin_lock_irqsave ( & garmin_data_p - > lock , flags ) ;
garmin_data_p - > flags & = ~ FLAGS_BULK_IN_ACTIVE ;
spin_unlock_irqrestore ( & garmin_data_p - > lock , flags ) ;
2005-04-17 02:20:36 +04:00
}
}
2008-07-22 14:11:44 +04:00
static void garmin_read_int_callback ( struct urb * urb )
2005-04-17 02:20:36 +04:00
{
2006-07-11 21:41:33 +04:00
unsigned long flags ;
2007-06-16 02:44:13 +04:00
int retval ;
2008-02-24 13:41:47 +03:00
struct usb_serial_port * port = urb - > context ;
2008-07-22 14:11:44 +04:00
struct garmin_data * garmin_data_p = usb_get_serial_port_data ( port ) ;
2005-04-17 02:20:36 +04:00
unsigned char * data = urb - > transfer_buffer ;
2007-06-16 02:44:13 +04:00
int status = urb - > status ;
2005-04-17 02:20:36 +04:00
2007-06-16 02:44:13 +04:00
switch ( status ) {
2005-04-17 02:20:36 +04:00
case 0 :
/* success */
break ;
case - ECONNRESET :
case - ENOENT :
case - ESHUTDOWN :
/* this urb is terminated, clean up */
2012-09-14 22:50:30 +04:00
dev_dbg ( & urb - > dev - > dev , " %s - urb shutting down with status: %d \n " ,
2008-03-04 03:08:34 +03:00
__func__ , status ) ;
2005-04-17 02:20:36 +04:00
return ;
default :
2012-09-14 22:50:30 +04:00
dev_dbg ( & urb - > dev - > dev , " %s - nonzero urb status received: %d \n " ,
2008-03-04 03:08:34 +03:00
__func__ , status ) ;
2005-04-17 02:20:36 +04:00
return ;
}
2012-09-18 12:58:57 +04:00
usb_serial_debug_data ( & port - > dev , __func__ , urb - > actual_length ,
urb - > transfer_buffer ) ;
2005-04-17 02:20:36 +04:00
if ( urb - > actual_length = = sizeof ( GARMIN_BULK_IN_AVAIL_REPLY ) & &
2016-02-04 21:01:27 +03:00
memcmp ( data , GARMIN_BULK_IN_AVAIL_REPLY ,
sizeof ( GARMIN_BULK_IN_AVAIL_REPLY ) ) = = 0 ) {
2005-04-17 02:20:36 +04:00
2012-09-14 22:50:30 +04:00
dev_dbg ( & port - > dev , " %s - bulk data available. \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
2016-02-04 21:01:27 +03:00
if ( ( garmin_data_p - > flags & FLAGS_BULK_IN_ACTIVE ) = = 0 ) {
2006-07-11 21:41:33 +04:00
/* bulk data available */
2007-06-16 02:44:13 +04:00
retval = usb_submit_urb ( port - > read_urb , GFP_ATOMIC ) ;
if ( retval ) {
2006-07-11 21:41:33 +04:00
dev_err ( & port - > dev ,
2008-07-22 14:11:44 +04:00
" %s - failed submitting read urb, error %d \n " ,
__func__ , retval ) ;
2006-07-11 21:41:33 +04:00
} else {
spin_lock_irqsave ( & garmin_data_p - > lock , flags ) ;
garmin_data_p - > flags | = FLAGS_BULK_IN_ACTIVE ;
2008-07-22 14:11:44 +04:00
spin_unlock_irqrestore ( & garmin_data_p - > lock ,
flags ) ;
2006-07-11 21:41:33 +04:00
}
} 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 ) ;
2005-04-17 02:20:36 +04:00
}
} else if ( urb - > actual_length = = ( 4 + sizeof ( GARMIN_START_SESSION_REPLY ) )
2016-02-04 21:01:27 +03:00
& & memcmp ( data , GARMIN_START_SESSION_REPLY ,
sizeof ( GARMIN_START_SESSION_REPLY ) ) = = 0 ) {
2005-04-17 02:20:36 +04:00
2006-07-11 21:41:33 +04:00
spin_lock_irqsave ( & garmin_data_p - > lock , flags ) ;
2005-04-17 02:20:36 +04:00
garmin_data_p - > flags | = FLAGS_SESSION_REPLY1_SEEN ;
2006-07-11 21:41:33 +04:00
spin_unlock_irqrestore ( & garmin_data_p - > lock , flags ) ;
2005-04-17 02:20:36 +04:00
/* save the serial number */
2008-07-22 14:11:44 +04:00
garmin_data_p - > serial_num = __le32_to_cpup (
( __le32 * ) ( data + GARMIN_PKTHDR_LENGTH ) ) ;
2005-04-17 02:20:36 +04:00
2012-09-14 22:50:30 +04:00
dev_dbg ( & port - > dev , " %s - start-of-session reply seen - serial %u. \n " ,
2008-03-04 03:08:34 +03:00
__func__ , garmin_data_p - > serial_num ) ;
2005-04-17 02:20:36 +04:00
}
2011-04-29 10:58:43 +04:00
garmin_read_process ( garmin_data_p , data , urb - > actual_length , 0 ) ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:11:44 +04:00
retval = usb_submit_urb ( urb , GFP_ATOMIC ) ;
2007-06-16 02:44:13 +04:00
if ( retval )
2005-04-17 02:20:36 +04:00
dev_err ( & urb - > dev - > dev ,
" %s - Error %d submitting interrupt urb \n " ,
2008-03-04 03:08:34 +03:00
__func__ , retval ) ;
2005-04-17 02:20:36 +04:00
}
/*
* Sends the next queued packt to the tty port ( garmin native mode only )
* and then sets a timer to call itself again until all queued data
* is sent .
*/
2008-07-22 14:11:44 +04:00
static int garmin_flush_queue ( struct garmin_data * garmin_data_p )
2005-04-17 02:20:36 +04:00
{
2006-07-11 21:41:33 +04:00
unsigned long flags ;
2005-04-17 02:20:36 +04:00
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 {
2006-07-11 21:41:33 +04:00
spin_lock_irqsave ( & garmin_data_p - > lock , flags ) ;
2005-04-17 02:20:36 +04:00
garmin_data_p - > flags & = ~ FLAGS_QUEUING ;
2006-07-11 21:41:33 +04:00
spin_unlock_irqrestore ( & garmin_data_p - > lock , flags ) ;
2005-04-17 02:20:36 +04:00
}
}
return 0 ;
}
2008-07-22 14:09:07 +04:00
static void garmin_throttle ( struct tty_struct * tty )
2005-04-17 02:20:36 +04:00
{
2008-07-22 14:09:07 +04:00
struct usb_serial_port * port = tty - > driver_data ;
2008-07-22 14:11:44 +04:00
struct garmin_data * garmin_data_p = usb_get_serial_port_data ( port ) ;
2005-04-17 02:20:36 +04:00
/* set flag, data received will be put into a queue
for later processing */
2009-10-07 12:50:23 +04:00
spin_lock_irq ( & garmin_data_p - > lock ) ;
2005-04-17 02:20:36 +04:00
garmin_data_p - > flags | = FLAGS_QUEUING | FLAGS_THROTTLED ;
2009-10-07 12:50:23 +04:00
spin_unlock_irq ( & garmin_data_p - > lock ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-22 14:11:44 +04:00
static void garmin_unthrottle ( struct tty_struct * tty )
2005-04-17 02:20:36 +04:00
{
2008-07-22 14:09:07 +04:00
struct usb_serial_port * port = tty - > driver_data ;
2008-07-22 14:11:44 +04:00
struct garmin_data * garmin_data_p = usb_get_serial_port_data ( port ) ;
2006-07-11 21:41:33 +04:00
int status ;
2005-04-17 02:20:36 +04:00
2009-10-07 12:50:23 +04:00
spin_lock_irq ( & garmin_data_p - > lock ) ;
2005-04-17 02:20:36 +04:00
garmin_data_p - > flags & = ~ FLAGS_THROTTLED ;
2009-10-07 12:50:23 +04:00
spin_unlock_irq ( & garmin_data_p - > lock ) ;
2005-04-17 02:20:36 +04:00
/* 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 ) ;
2006-07-11 21:41:33 +04:00
2016-02-04 21:01:27 +03:00
if ( ( garmin_data_p - > flags & FLAGS_BULK_IN_ACTIVE ) ! = 0 ) {
2009-10-07 12:50:23 +04:00
status = usb_submit_urb ( port - > read_urb , GFP_KERNEL ) ;
2006-07-11 21:41:33 +04:00
if ( status )
dev_err ( & port - > dev ,
" %s - failed resubmitting read urb, error %d \n " ,
2008-03-04 03:08:34 +03:00
__func__ , status ) ;
2006-07-11 21:41:33 +04:00
}
2005-04-17 02:20:36 +04:00
}
/*
* The timer is currently only used to send queued packets to
* the tty in cases where the protocol provides no own handshaking
* to initiate the transfer .
*/
2017-10-10 21:25:22 +03:00
static void timeout_handler ( struct timer_list * t )
2005-04-17 02:20:36 +04:00
{
2017-10-10 21:25:22 +03:00
struct garmin_data * garmin_data_p = from_timer ( garmin_data_p , t , timer ) ;
2005-04-17 02:20:36 +04:00
/* send the next queued packet to the tty port */
if ( garmin_data_p - > mode = = MODE_NATIVE )
if ( garmin_data_p - > flags & FLAGS_QUEUING )
garmin_flush_queue ( garmin_data_p ) ;
}
2012-10-10 22:10:21 +04:00
static int garmin_port_probe ( struct usb_serial_port * port )
2005-04-17 02:20:36 +04:00
{
2012-10-10 22:10:21 +04:00
int status ;
struct garmin_data * garmin_data_p ;
2005-04-17 02:20:36 +04:00
2006-11-22 21:54:38 +03:00
garmin_data_p = kzalloc ( sizeof ( struct garmin_data ) , GFP_KERNEL ) ;
2013-12-29 22:22:56 +04:00
if ( ! garmin_data_p )
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
2013-12-29 22:22:56 +04:00
2017-10-10 21:25:22 +03:00
timer_setup ( & garmin_data_p - > timer , timeout_handler , 0 ) ;
2005-04-17 02:20:36 +04:00
spin_lock_init ( & garmin_data_p - > lock ) ;
INIT_LIST_HEAD ( & garmin_data_p - > pktlist ) ;
garmin_data_p - > port = port ;
garmin_data_p - > state = 0 ;
2011-04-29 10:58:43 +04:00
garmin_data_p - > flags = 0 ;
2005-04-17 02:20:36 +04:00
garmin_data_p - > count = 0 ;
2017-10-11 15:02:57 +03:00
init_usb_anchor ( & garmin_data_p - > write_urbs ) ;
2005-04-17 02:20:36 +04:00
usb_set_serial_port_data ( port , garmin_data_p ) ;
status = garmin_init_session ( port ) ;
2017-10-11 15:02:58 +03:00
if ( status )
goto err_free ;
return 0 ;
err_free :
kfree ( garmin_data_p ) ;
2005-04-17 02:20:36 +04:00
return status ;
}
2012-10-10 22:10:21 +04:00
static int garmin_port_remove ( struct usb_serial_port * port )
2005-04-17 02:20:36 +04:00
{
2008-07-22 14:11:44 +04:00
struct garmin_data * garmin_data_p = usb_get_serial_port_data ( port ) ;
2005-04-17 02:20:36 +04:00
2017-10-11 15:02:57 +03:00
usb_kill_anchored_urbs ( & garmin_data_p - > write_urbs ) ;
2008-07-22 14:11:44 +04:00
usb_kill_urb ( port - > interrupt_in_urb ) ;
2005-04-17 02:20:36 +04:00
del_timer_sync ( & garmin_data_p - > timer ) ;
2008-07-22 14:11:44 +04:00
kfree ( garmin_data_p ) ;
2012-10-10 22:10:21 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
/* All of the device info needed */
2005-06-21 08:15:16 +04:00
static struct usb_serial_driver garmin_device = {
2005-06-21 08:15:16 +04:00
. driver = {
2006-07-11 21:41:33 +04:00
. owner = THIS_MODULE ,
. name = " garmin_gps " ,
2005-06-21 08:15:16 +04:00
} ,
2006-07-11 21:41:33 +04:00
. description = " Garmin GPS usb/tty " ,
2005-04-17 02:20:36 +04:00
. id_table = id_table ,
. num_ports = 1 ,
. open = garmin_open ,
. close = garmin_close ,
. throttle = garmin_throttle ,
. unthrottle = garmin_unthrottle ,
2012-10-10 22:10:21 +04:00
. port_probe = garmin_port_probe ,
. port_remove = garmin_port_remove ,
2005-04-17 02:20:36 +04:00
. write = garmin_write ,
. write_room = garmin_write_room ,
. write_bulk_callback = garmin_write_bulk_callback ,
. read_bulk_callback = garmin_read_bulk_callback ,
. read_int_callback = garmin_read_int_callback ,
} ;
2012-02-23 23:56:32 +04:00
static struct usb_serial_driver * const serial_drivers [ ] = {
& garmin_device , NULL
} ;
2005-04-17 02:20:36 +04:00
2012-05-09 02:46:14 +04:00
module_usb_serial_driver ( serial_drivers , id_table ) ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:11:44 +04:00
MODULE_AUTHOR ( DRIVER_AUTHOR ) ;
MODULE_DESCRIPTION ( DRIVER_DESC ) ;
2005-04-17 02:20:36 +04:00
MODULE_LICENSE ( " GPL " ) ;
module_param ( initial_mode , int , S_IRUGO ) ;
MODULE_PARM_DESC ( initial_mode , " Initial mode " ) ;